如何从Java方法返回多个对象?

Jag*_*mal 165 java return

我想从Java方法返回两个对象,并想知道这样做的好方法是什么?

我能想到的可能的方法是:返回HashMap(因为这两个对象是相关的),或者返回ArrayListObject对象.

更确切地说,我想要返回的两个对象是(a)List对象和(b)逗号分隔的对象.

我想从一个方法返回这两个对象,因为我不想遍历对象列表以获取逗号分隔的名称(我可以在此方法的同一循环中执行).

不知何故,返回a HashMap看起来并不是一种非常优雅的方式.

Joa*_*uer 123

如果要返回两个对象,通常需要返回一个封装两个对象的对象.

你可以NamedObject像这样返回一个对象列表:

public class NamedObject<T> {
  public final String name;
  public final T object;

  public NamedObject(String name, T object) {
    this.name = name;
    this.object = object;
  }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以轻松返回一个List<NamedObject<WhateverTypeYouWant>>.

另外:为什么要返回以逗号分隔的名称列表而不是List<String>?或者更好的是,返回a Map<String,TheObjectType>,其中键是对象的名称和值(除非您的对象具有指定的顺序,在这种情况下,NavigableMap可能是您想要的.

  • 我一直想知道为什么Java由于这个原因没有Pair &lt;T,U&gt;类。 (2认同)

Dav*_*nak 65

如果您知道要返回两个对象,也可以使用通用对:

public class Pair<A,B> {
    public final A a;
    public final B b;

    public Pair(A a, B b) {
        this.a = a;
        this.b = b;
    }
};
Run Code Online (Sandbox Code Playgroud)

编辑上面更完整形成的实现:

package util;

public class Pair<A,B> {

    public static <P, Q> Pair<P, Q> makePair(P p, Q q) {
        return new Pair<P, Q>(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 <P, Q> Pair<P, Q> cast(Pair<?, ?> pair, Class<P> pClass, Class<Q> qClass) {

        if (pair.isInstance(pClass, qClass)) {
            return (Pair<P, Q>) pair;
        }

        throw new ClassCastException();

    }

}
Run Code Online (Sandbox Code Playgroud)

注意事项,主要围绕Java和泛型的生锈:

  • 这两个ab是不可变的.
  • makePair静态方法可以帮助您进行锅炉板打字,Java 7中的钻石操作员不会那么烦人.有一些工作可以使这个非常好的re:泛型,但它现在应该是好的.(参见PECS)
  • hashcode并且equals通过蚀产生.
  • 方法中的编译时间cast是正常的,但似乎不太正确.
  • 我不确定是否isInstance有必要使用通配符.
  • 我刚刚写了这篇文章以回应评论,仅用于说明目的.

  • 这是一个非常好的`Pair`实现.我做的一个小改动:向`ClassCastException`添加一条消息.否则,如果由于某种原因失败,调试将成为一场噩梦.(并且如果你转换为`Pair <?,?>`(这是有效的,因为你只需要来自`a`和`b`的`Object`方法),就不需要rawtypes suppress-warnings.你介意我调整代码? (2认同)

Kyl*_*ski 25

如果您调用的方法是私有的,或从一个位置调用,请尝试

return new Object[]{value1, value2};
Run Code Online (Sandbox Code Playgroud)

来电者看起来像:

Object[] temp=myMethod(parameters);
Type1 value1=(Type1)temp[0];  //For code clarity: temp[0] is not descriptive
Type2 value2=(Type2)temp[1];
Run Code Online (Sandbox Code Playgroud)

David Hanak的Pair示例没有语法上的好处,并且仅限于两个值.

return new Pair<Type1,Type2>(value1, value2);
Run Code Online (Sandbox Code Playgroud)

来电者看起来像:

Pair<Type1, Type2> temp=myMethod(parameters);
Type1 value1=temp.a;  //For code clarity: temp.a is not descriptive
Type2 value2=temp.b;
Run Code Online (Sandbox Code Playgroud)

  • 对具有类型控制权益 (6认同)
  • 恕我直言,不要这样做 - 宣言说的预期回报值太少了.AFAIK,更广泛地优先创建通用类,指定返回的参数数量以及这些参数的类型.`Pair <T1,T2>`,`Tuple <T1,T2,T3>`,`Tuple <T1,T2,T3,T4>`等等.然后一个特定用途显示参数的数量和类型`Pair <int ,String> temp = ...`或者其他什么. (4认同)

Via*_*nin 21

您可以使用以下任何一种方式:

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";
Run Code Online (Sandbox Code Playgroud)

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]);
}
Run Code Online (Sandbox Code Playgroud)

2)使用ArrayList

private static List<String> methodWithListResult() {
    //...
    return Arrays.asList("valueA", "valueB");
}

private static void usingListResultTest() {
    List<String> result = methodWithListResult();
    System.out.println();
    System.out.println("A = " + result.get(VALUE_A));
    System.out.println("B = " + result.get(VALUE_B));
}
Run Code Online (Sandbox Code Playgroud)

3)使用HashMap

private static Map<String, String> methodWithMapResult() {
    Map<String, String> result = new HashMap<>(RETURN_COUNT);
    result.put(A, "valueA");
    result.put(B, "valueB");
    //...
    return result;
}

private static void usingMapResultTest() {
    Map<String, String> result = methodWithMapResult();
    System.out.println();
    System.out.println("A = " + result.get(A));
    System.out.println("B = " + result.get(B));
}
Run Code Online (Sandbox Code Playgroud)

4)使用您的自定义容器类

private static class MyContainer<M,N> {
    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<String, String> methodWithContainerResult() {
    //...
    return new MyContainer("valueA", "valueB");
}

private static void usingContainerResultTest() {
    MyContainer<String, String> result = methodWithContainerResult();
    System.out.println();
    System.out.println("A = " + result.getFirst());
    System.out.println("B = " + result.getSecond());
}
Run Code Online (Sandbox Code Playgroud)

5)使用AbstractMap.simpleEntry

private static AbstractMap.SimpleEntry<String, String> methodWithAbstractMapSimpleEntryResult() {
    //...
    return new AbstractMap.SimpleEntry<>("valueA", "valueB");
}

private static void usingAbstractMapSimpleResultTest() {
    AbstractMap.SimpleEntry<String, String> result = methodWithAbstractMapSimpleEntryResult();
    System.out.println();
    System.out.println("A = " + result.getKey());
    System.out.println("B = " + result.getValue());
}
Run Code Online (Sandbox Code Playgroud)

6)利用一对Apache的百科全书

private static Pair<String, String> methodWithPairResult() {
    //...
    return new ImmutablePair<>("valueA", "valueB");
}

private static void usingPairResultTest() {
    Pair<String, String> result = methodWithPairResult();
    System.out.println();
    System.out.println("A = " + result.getKey());
    System.out.println("B = " + result.getValue());
}
Run Code Online (Sandbox Code Playgroud)


Ulr*_*sen 15

当我用Java编写代码时,我几乎总是最终定义n-Tuple类.例如:

public class Tuple2<T1,T2> {
  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;}
}
Run Code Online (Sandbox Code Playgroud)

我知道它有点难看,但它有效,你只需要定义一次元组类型.元组是Java真正缺乏的东西.

编辑:David Hanak的例子更优雅,因为它避免了定义getter并仍然保持对象不可变.


giz*_*zmo 10

我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源.

D. Knuth

  • 我认为OP并不是在询问性能,而是关于正确的风格,惯用的方式. (23认同)

kip*_*ipz 9

在Java 5之前,我有点同意Map解决方案并不理想.它不会为您提供编译时类型检查,因此可能会在运行时导致问题.但是,使用Java 5,我们有通用类型.

所以你的方法看起来像这样:

public Map<String, MyType> doStuff();
Run Code Online (Sandbox Code Playgroud)

MyType当然是您要返回的对象类型.

基本上我认为在这种情况下返回Map是正确的解决方案,因为这正是您想要返回的 - 字符串到对象的映射.


小智 6

或者,在我想从方法中返回许多内容的情况下,我有时会使用回调机制而不是容器.这在我无法提前指定将生成多少对象的情况下非常有效.

对于您的特定问题,它看起来像这样:

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 );
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

使用以下条目对象示例:

public Entry<A,B> methodname(arg)
{
.......

return new AbstractMap.simpleEntry<A,B>(instanceOfA,instanceOfB);
}
Run Code Online (Sandbox Code Playgroud)


小智 5

关于一般的多个返回值的问题,我通常使用一个包装单个返回值的小助手类,并作为参数传递给方法:

public class ReturnParameter<T> {
    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; }
}
Run Code Online (Sandbox Code Playgroud)

(对于原始数据类型,我使用较小的变量来直接存储值)

然后,将声明一个想要返回多个值的方法,如下所示:

public void methodThatReturnsTwoValues(ReturnParameter<ClassA> nameForFirstValueToReturn, ReturnParameter<ClassB> nameForSecondValueToReturn) {
    //...
    nameForFirstValueToReturn.set("...");
    nameForSecondValueToReturn.set("...");
    //...
}
Run Code Online (Sandbox Code Playgroud)

也许主要的缺点是调用者必须提前准备返回对象以防他想要使用它们(并且该方法应该检查空指针)

ReturnParameter<ClassA> nameForFirstValue = new ReturnParameter<ClassA>();
ReturnParameter<ClassB> nameForSecondValue = new ReturnParameter<ClassB>();
methodThatReturnsTwoValues(nameForFirstValue, nameForSecondValue);
Run Code Online (Sandbox Code Playgroud)

优点(与提出的其他解决方案相比):

  • 您不必为单个方法及其返回类型创建特殊的类声明
  • 参数获得名称,因此在查看方法签名时更容易区分
  • 为每个参数键入安全性


jac*_*cob 5

Apache Commons为此提供了元组和三元组:

  • ImmutablePair<L,R> 由两个Object元素组成的不可变对。
  • ImmutableTriple<L,M,R> 一个不变的三元组,由三个Object元素组成。
  • MutablePair<L,R> 由两个Object元素组成的可变对。
  • MutableTriple<L,M,R> 可变的三元组,由三个Object元素组成。
  • Pair<L,R> 一对,由两个元素组成。
  • Triple<L,M,R> 由三个元素组成的三元组。

来源:https : //commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html


ser*_*inc 5

在您的情况下,注释可能是一个不错的选择,但在Android中,您可以使用Pair 。只是

return new Pair<>(yourList, yourCommaSeparatedValues);
Run Code Online (Sandbox Code Playgroud)