我想从Java方法返回两个对象,并想知道这样做的好方法是什么?
我能想到的可能的方法是:返回HashMap
(因为这两个对象是相关的),或者返回ArrayList
的Object
对象.
更确切地说,我想要返回的两个对象是(a)List
对象和(b)逗号分隔的对象.
我想从一个方法返回这两个对象,因为我不想遍历对象列表以获取逗号分隔的名称(我可以在此方法的同一循环中执行).
不知何故,返回a HashMap
看起来并不是一种非常优雅的方式.
如果要返回两个对象,通常需要返回一个封装两个对象的对象.
你可以NamedObject
像这样返回一个对象列表:
public class NamedObject{ public final String name; public final T object; public NamedObject(String name, T object) { this.name = name; this.object = object; } }
然后你可以轻松返回一个List
.
另外:为什么要返回以逗号分隔的名称列表而不是List
?或者更好的是,返回a Map
,其中键是对象的名称和值(除非您的对象具有指定的顺序,在这种情况下,NavigableMap
可能是您想要的.
如果您知道要返回两个对象,也可以使用通用对:
public class Pair { public final A a; public final B b; public Pair(A a, B b) { this.a = a; this.b = b; } };
编辑上面更完整形成的实现:
package util; public class Pair { public staticPair
makePair(P p, Q q) { return new Pair
(p, q); } public final A a; public final B b; public Pair(A a, B b) { this.a = a; this.b = b; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((a == null) ? 0 : a.hashCode()); result = prime * result + ((b == null) ? 0 : b.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } @SuppressWarnings("rawtypes") Pair other = (Pair) obj; if (a == null) { if (other.a != null) { return false; } } else if (!a.equals(other.a)) { return false; } if (b == null) { if (other.b != null) { return false; } } else if (!b.equals(other.b)) { return false; } return true; } public boolean isInstance(Class> classA, Class> classB) { return classA.isInstance(a) && classB.isInstance(b); } @SuppressWarnings("unchecked") public static
Pair
cast(Pair, ?> pair, Class
pClass, Class
qClass) { if (pair.isInstance(pClass, qClass)) { return (Pair) pair; } throw new ClassCastException(); } }
注意事项,主要围绕Java和泛型的生锈:
这两个a
和b
是不可变的.
makePair
静态方法可以帮助您进行锅炉板打字,Java 7中的钻石操作员不会那么烦人.有一些工作可以使这个非常好的re:泛型,但它现在应该是好的.(参见PECS)
hashcode
并且equals
通过蚀产生.
方法中的编译时间cast
是正常的,但似乎不太正确.
我不确定是否isInstance
有必要使用通配符.
我刚刚写了这篇文章以回应评论,仅用于说明目的.
如果您调用的方法是私有的,或从一个位置调用,请尝试
return new Object[]{value1, value2};
来电者看起来像:
Object[] temp=myMethod(parameters); Type1 value1=(Type1)temp[0]; //For code clarity: temp[0] is not descriptive Type2 value2=(Type2)temp[1];
David Hanak的Pair示例没有语法上的好处,并且仅限于两个值.
return new Pair(value1, value2);
来电者看起来像:
Pairtemp=myMethod(parameters); Type1 value1=temp.a; //For code clarity: temp.a is not descriptive Type2 value2=temp.b;
您可以使用以下任何一种方式:
private static final int RETURN_COUNT = 2; private static final int VALUE_A = 0; private static final int VALUE_B = 1; private static final String A = "a"; private static final String B = "b";
1)使用数组
private static String[] methodWithArrayResult() { //... return new String[]{"valueA", "valueB"}; } private static void usingArrayResultTest() { String[] result = methodWithArrayResult(); System.out.println(); System.out.println("A = " + result[VALUE_A]); System.out.println("B = " + result[VALUE_B]); }
2)使用ArrayList
private static ListmethodWithListResult() { //... return Arrays.asList("valueA", "valueB"); } private static void usingListResultTest() { List result = methodWithListResult(); System.out.println(); System.out.println("A = " + result.get(VALUE_A)); System.out.println("B = " + result.get(VALUE_B)); }
3)使用HashMap
private static MapmethodWithMapResult() { Map result = new HashMap<>(RETURN_COUNT); result.put(A, "valueA"); result.put(B, "valueB"); //... return result; } private static void usingMapResultTest() { Map result = methodWithMapResult(); System.out.println(); System.out.println("A = " + result.get(A)); System.out.println("B = " + result.get(B)); }
4)使用您的自定义容器类
private static class MyContainer{ private final M first; private final N second; public MyContainer(M first, N second) { this.first = first; this.second = second; } public M getFirst() { return first; } public N getSecond() { return second; } // + hashcode, equals, toString if need } private static MyContainer methodWithContainerResult() { //... return new MyContainer("valueA", "valueB"); } private static void usingContainerResultTest() { MyContainer result = methodWithContainerResult(); System.out.println(); System.out.println("A = " + result.getFirst()); System.out.println("B = " + result.getSecond()); }
5)使用AbstractMap.simpleEntry
private static AbstractMap.SimpleEntrymethodWithAbstractMapSimpleEntryResult() { //... return new AbstractMap.SimpleEntry<>("valueA", "valueB"); } private static void usingAbstractMapSimpleResultTest() { AbstractMap.SimpleEntry result = methodWithAbstractMapSimpleEntryResult(); System.out.println(); System.out.println("A = " + result.getKey()); System.out.println("B = " + result.getValue()); }
6)利用一对的Apache的百科全书
private static PairmethodWithPairResult() { //... return new ImmutablePair<>("valueA", "valueB"); } private static void usingPairResultTest() { Pair result = methodWithPairResult(); System.out.println(); System.out.println("A = " + result.getKey()); System.out.println("B = " + result.getValue()); }
当我用Java编写代码时,我几乎总是最终定义n-Tuple类.例如:
public class Tuple2{ private T1 f1; private T2 f2; public Tuple2(T1 f1, T2 f2) { this.f1 = f1; this.f2 = f2; } public T1 getF1() {return f1;} public T2 getF2() {return f2;} }
我知道它有点难看,但它有效,你只需要定义一次元组类型.元组是Java真正缺乏的东西.
编辑:David Hanak的例子更优雅,因为它避免了定义getter并仍然保持对象不可变.
我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源.
D. Knuth
在Java 5之前,我有点同意Map解决方案并不理想.它不会为您提供编译时类型检查,因此可能会在运行时导致问题.但是,使用Java 5,我们有通用类型.
所以你的方法看起来像这样:
public MapdoStuff();
MyType当然是您要返回的对象类型.
基本上我认为在这种情况下返回Map是正确的解决方案,因为这正是您想要返回的 - 字符串到对象的映射.
或者,在我想从方法中返回许多内容的情况下,我有时会使用回调机制而不是容器.这在我无法提前指定将生成多少对象的情况下非常有效.
对于您的特定问题,它看起来像这样:
public class ResultsConsumer implements ResultsGenerator.ResultsCallback { public void handleResult( String name, Object value ) { ... } } public class ResultsGenerator { public interface ResultsCallback { void handleResult( String aName, Object aValue ); } public void generateResults( ResultsGenerator.ResultsCallback aCallback ) { Object value = null; String name = null; ... aCallback.handleResult( name, value ); } }
关于一般的多个返回值的问题,我通常使用一个包装单个返回值的小助手类,并作为参数传递给方法:
public class ReturnParameter{ private T value; public ReturnParameter() { this.value = null; } public ReturnParameter(T initialValue) { this.value = initialValue; } public void set(T value) { this.value = value; } public T get() { return this.value; } }
(对于原始数据类型,我使用较小的变量来直接存储值)
然后,将声明一个想要返回多个值的方法,如下所示:
public void methodThatReturnsTwoValues(ReturnParameternameForFirstValueToReturn, ReturnParameter nameForSecondValueToReturn) { //... nameForFirstValueToReturn.set("..."); nameForSecondValueToReturn.set("..."); //... }
也许主要的缺点是调用者必须提前准备返回对象以防他想要使用它们(并且该方法应该检查空指针)
ReturnParameternameForFirstValue = new ReturnParameter (); ReturnParameter nameForSecondValue = new ReturnParameter (); methodThatReturnsTwoValues(nameForFirstValue, nameForSecondValue);
优点(与提出的其他解决方案相比):
您不必为单个方法及其返回类型创建特殊的类声明
参数获得名称,因此在查看方法签名时更容易区分
为每个参数键入安全性
Apache Commons为此提供了元组和三元组:
ImmutablePair
由两个Object元素组成的不可变对。
ImmutableTriple
一个不变的三元组,由三个Object元素组成。
MutablePair
由两个Object元素组成的可变对。
MutableTriple
可变的三元组,由三个Object元素组成。
Pair
一对,由两个元素组成。
Triple
由三个元素组成的三元组。
来源:https : //commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html
在您的情况下,注释可能是一个不错的选择,但在Android中,您可以使用Pair
。只是
return new Pair<>(yourList, yourCommaSeparatedValues);