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

如何从Java方法返回多个对象?,java,return,Java,Return,我想从Java方法返回两个对象,我想知道这样做的好方法是什么 我可以想到的可能方法是:返回HashMap(因为这两个对象是相关的)或返回Object对象的ArrayList 更准确地说,我要返回的两个对象是(a)List对象和(b)逗号分隔的名称 我想从一个方法返回这两个对象,因为我不想遍历对象列表来获得逗号分隔的名称(我可以在这个方法的同一个循环中这样做) 不知何故,返回一个HashMap看起来并不是一个非常优雅的方法。如果要返回两个对象,通常需要返回一个封装这两个对象的对象 您可以返回Nam

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

我可以想到的可能方法是:返回
HashMap
(因为这两个对象是相关的)或返回
Object
对象的
ArrayList

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

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


不知何故,返回一个
HashMap
看起来并不是一个非常优雅的方法。

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

您可以返回
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;
  }
}
public Map<String, MyType> doStuff();
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 String buildList(List<?> list) {
    list.add(1);
    list.add(2);
    list.add(3);
    return "something,something,something,dark side";
}
List<?> values = new ArrayList<?>();
String names = buildList(values);
public Pair<ResultMessage, List<Customer>> getCustomers() {
    List<Customer> list = new ArrayList<Customer>();
    try {
    /*
    * Do some work to get the list of Customers from the DB
    * */
    } catch (SQLException e) {
        return Pair.of(
                       new ResultMessage(e.getErrorCode(), e.getMessage()), // Left 
                       null);  // Right
    }
    return Pair.of(
                   new ResultMessage(0, "SUCCESS"), // Left 
                   list); // Right
}
公共类NamedObject{
公共最终字符串名;
公共最终目标;
公共名称对象(字符串名称,T对象){
this.name=名称;
this.object=对象;
}
}
然后您可以轻松返回
列表


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

所有可能的解决方案都将是一个乱码(与容器对象一样,您的HashMap思想是通过数组实现的“多个返回值”)。我建议从返回的列表中重新生成逗号分隔的列表。代码最终会更干净。

在Java 5之前,我同意映射解决方案并不理想。它不会提供编译时类型检查,因此可能会在运行时引起问题。但是,对于Java 5,我们有泛型类型

因此,您的方法可以如下所示:

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

  public NamedObject(String name, T object) {
    this.name = name;
    this.object = object;
  }
}
public Map<String, MyType> doStuff();
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 String buildList(List<?> list) {
    list.add(1);
    list.add(2);
    list.add(3);
    return "something,something,something,dark side";
}
List<?> values = new ArrayList<?>();
String names = buildList(values);
public Pair<ResultMessage, List<Customer>> getCustomers() {
    List<Customer> list = new ArrayList<Customer>();
    try {
    /*
    * Do some work to get the list of Customers from the DB
    * */
    } catch (SQLException e) {
        return Pair.of(
                       new ResultMessage(e.getErrorCode(), e.getMessage()), // Left 
                       null);  // Right
    }
    return Pair.of(
                   new ResultMessage(0, "SUCCESS"), // Left 
                   list); // Right
}
publicmap doStuff();
MyType当然是您要返回的对象的类型


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

在我看来,这里有三种选择,解决方案取决于上下文。您可以选择在生成li的方法中实现名称的构造st.这是您选择的选项,但我认为它不是最好的。您正在创建生产者方法与消费方法之间的耦合,该耦合不需要存在。其他调用方可能不需要额外的信息,您将为这些调用方计算额外的信息

或者,您可以让调用方法计算名称。如果只有一个调用方需要此信息,您可以到此为止。您没有额外的依赖项,虽然有一些额外的计算,但您避免了使构造方法过于具体。这是一个很好的权衡

最后,您可以让列表本身负责创建名称。如果计算需要由多个调用方完成,这就是我将采用的方法。我认为这将负责创建与对象本身最密切相关的类的名称

在后一种情况下,我的解决方案是创建一个专门的列表类,该类返回一个逗号分隔的字符串,该字符串由它所包含的对象的名称组成。使该类足够智能,以便在添加和删除对象时动态构造名称字符串。然后返回此列表的实例并调用名称生成方法尽管需要简单地延迟计算名称直到第一次调用方法并存储它(然后加载),如果添加或删除对象,只需要删除计算值并在下一次调用中重新计算。C++中的

< P>(STL)有一个pair类用于捆绑两个对象。在Java泛型中,pair类不可用,尽管有一些可用的pair类。不过,您可以自己轻松实现它


但是,我同意其他一些答案,即如果需要从一个方法返回两个或多个对象,最好将它们封装在一个类中。

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

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;
    }
};
公共类对{
公开决赛A;
公开决赛B;
公共对(A、B){
这个a=a;
这个.b=b;
}
};
编辑上述内容的更完整的实现:

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();

    }

}
package-util;
公共类对{
公共静态对makePair(P,Q){
返回新对(p,q);
}
公开决赛A;
公开决赛B;
公共对(A、B){
这个a=a;
这个.b=b;
}
@凌驾
公共int hashCode(){
最终整数素数=31;
int结果=1;
result=prime*result+((a==null)?0:a.hashCode();
result=prime*result+((b==null)?0:b.hashCode();
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj){
返回true;
}
if(obj==null){
返回false;
}
如果(getClass()!=obj.getClass()){
返回false;
}
@抑制警告(“原始类型”)
配对其他=(配对)obj;
如果(a==null){
if(other.a!=null){
返回false;
}
}如果(!a.equals(other.a)){
返回false;
}
如果(b==null){
if(other.b!=null){
返回false;
}
}else如果(!b.equals(other.b)){
返回false;
}
返回true;
}
public class Tuple {
private Object[] multiReturns;

private Tuple(Object... multiReturns) {
    this.multiReturns = multiReturns;
}

public static Tuple _t(Object... multiReturns){
    return new Tuple(multiReturns);
}

public <T> T at(int index, Class<T> someClass) {
    return someClass.cast(multiReturns[index]);
}
}
public Tuple returnMultiValues(){
   return Tuple._t(new ArrayList(),new HashMap())
}


Tuple t = returnMultiValues();
ArrayList list = t.at(0,ArrayList.class);
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; }
}
public void methodThatReturnsTwoValues(ReturnParameter<ClassA> nameForFirstValueToReturn, ReturnParameter<ClassB> nameForSecondValueToReturn) {
    //...
    nameForFirstValueToReturn.set("...");
    nameForSecondValueToReturn.set("...");
    //...
}
ReturnParameter<ClassA> nameForFirstValue = new ReturnParameter<ClassA>();
ReturnParameter<ClassB> nameForSecondValue = new ReturnParameter<ClassB>();
methodThatReturnsTwoValues(nameForFirstValue, nameForSecondValue);
public String buildList(List<?> list) {
    list.add(1);
    list.add(2);
    list.add(3);
    return "something,something,something,dark side";
}
List<?> values = new ArrayList<?>();
String names = buildList(values);
public class Pair<L, R> {
    final L left;
    final R right;

    public Pair(L left, R right) {
        this.left = left;
        this.right = right;
    }

    public <T> T get(Class<T> param) {
        return (T) (param == this.left.getClass() ? this.left : this.right);
    }

    public static <L, R> Pair<L, R> of(L left, R right) {
        return new Pair<L, R>(left, right);
    }
}
public Pair<ResultMessage, List<Customer>> getCustomers() {
    List<Customer> list = new ArrayList<Customer>();
    try {
    /*
    * Do some work to get the list of Customers from the DB
    * */
    } catch (SQLException e) {
        return Pair.of(
                       new ResultMessage(e.getErrorCode(), e.getMessage()), // Left 
                       null);  // Right
    }
    return Pair.of(
                   new ResultMessage(0, "SUCCESS"), // Left 
                   list); // Right
}
void doSomething(){
    Pair<ResultMessage, List<Customer>> customerResult = _repository.getCustomers();
    if (customerResult.get(ResultMessage.class).getCode() == 0) {
        List<Customer> listOfCustomers = customerResult.get(List.class);
        System.out.println("do SOMETHING with the list ;) ");
    }else {
        System.out.println("Raised Error... do nothing!");
    }
}
[thingA, thingB] = createThings(...);  // just a conceptual syntax of method returning two values, not valid in Java
thingA = createThingA(...);
thingB = createThingB(thingA, ...);
[thingA, thingB] = createThings(...);  // see above
thingA = createThingA(...);
thingB = createThingB(...);
public ThingA createThingA(...) {
    doCommonThings(); // common logic
    // create thing A
}
public ThingB createThingB(...) {
    doCommonThings(); // common logic
    // create thing 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";
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]);
}
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));
}
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));
}
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());
}
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());
}
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());
}
return new Pair<>(yourList, yourCommaSeparatedValues);
multResult res = mydb.getInfo(); 
ArrayList<String> list= new ArrayList<String>();
add values to the list...
return new multResult("the message", list);
public class multResult {
    public String message; // or create a getter if you don't like public
    public ArrayList<String> list;
    multResult(String m, ArrayList<String> l){
        message = m;
        list= l;
}
public HashMap<String, Object> yourMethod()
{

   .... different logic here 

  HashMap<String, Object> returnHashMap = new HashMap<String, Object>();
  returnHashMap.put("objectA", objectAValue);
  returnHashMap.put("myString", myStringValue);
  returnHashMap.put("myBoolean", myBooleanValue);

  return returnHashMap;
}
// call the method
HashMap<String, Object> resultMap = yourMethod();
                
// fetch the results and cast them
ObjectA objectA = (ObjectA) resultMap.get("objectA");
String myString = (String) resultMap.get("myString");
Boolean myBoolean = (Boolean) resultMap.get("myBoolean");
import java.util.Objects;

public final class NTuple<V, T extends  NTuple<?, ?>> {
    private final V value;
    private final T next;

    private NTuple(V value, T next) {
        this.value = value;
        this.next = next;
    }

    public static <V> NTuple<V, ?> of(V value) {
        return new NTuple<>(value, null);
    }

    public static <V,  T extends  NTuple<?, ?>> NTuple<V, T> of(V value, T next) {
        return new NTuple<>(value, next);
    }

    public V value() {
        return value;
    }

    public T next() {
        return next;
    }

    public static <V> V unpack0(NTuple<V, ?> tuple) {
        return Objects.requireNonNull(tuple, "0").value();
    }

    public static <V, T extends NTuple<V, ?>> V unpack1(NTuple<?, T> tuple) {
        NTuple<?, T> tuple0 = Objects.requireNonNull(tuple, "0");
        NTuple<V, ?> tuple1 = Objects.requireNonNull(tuple0.next(), "1");
        return tuple1.value();
    }

    public static <V, T extends NTuple<?, NTuple<V, ?>>> V unpack2(NTuple<?, T> tuple) {
        NTuple<?, T> tuple0 = Objects.requireNonNull(tuple, "0");
        NTuple<?, NTuple<V, ?>> tuple1 = Objects.requireNonNull(tuple0.next(), "1");
        NTuple<V, ?> tuple2 = Objects.requireNonNull(tuple1.next(), "2");
        return tuple2.value();
    }
}
public static void main(String[] args) {
    // pre-java 10 without lombok - use lombok's var or java 10's var if you can
    NTuple<String, NTuple<Integer, NTuple<Integer, ?>>> multiple = wordCount("hello world");
    String original = NTuple.unpack0(multiple);
    Integer wordCount = NTuple.unpack1(multiple);
    Integer characterCount  = NTuple.unpack2(multiple);

    System.out.println(original + ": " + wordCount + " words " + characterCount + " chars");
}

private static NTuple<String, NTuple<Integer, NTuple<Integer, ?>>> wordCount(String s) {
    int nWords = s.split(" ").length;
    int nChars = s.length();
    return NTuple.of(s, NTuple.of(nWords, NTuple.of(nChars)));
}