¿Cómo devolver múltiples objetos de un método Java?

173

Quiero devolver dos objetos de un método Java y me preguntaba cuál podría ser una buena manera de hacerlo.

Las posibles formas en las que puedo pensar son: devolver a HashMap(ya que los dos Objetos están relacionados) o devolver un ArrayListde Objectobjetos.

Para ser más precisos, los dos objetos que quiero devolver son (a) Listde objetos y (b) nombres separados por comas de los mismos.

Quiero devolver estos dos objetos de un método porque no quiero recorrer la lista de objetos para obtener los nombres separados por comas (lo que puedo hacer en el mismo bucle en este método).

De alguna manera, devolver un HashMapno parece una forma muy elegante de hacerlo.

Jagmal
fuente
1
¿La Lista y los CSV son vistas básicamente diferentes de los mismos datos? Parece que lo que necesita es un Objeto donde tenga una Listreferencia única y una especie de tabla de búsqueda.
James P.
Pregunta relacionada: stackoverflow.com/questions/53453058/…
John McClane

Respuestas:

128

Si desea devolver dos objetos, generalmente desea devolver un solo objeto que encapsule los dos objetos.

Puede devolver una lista de NamedObjectobjetos como este:

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

  public NamedObject(String name, T object) {
    this.name = name;
    this.object = object;
  }
}

Entonces puede devolver fácilmente a List<NamedObject<WhateverTypeYouWant>>.

Además: ¿por qué querría devolver una lista de nombres separados por comas en lugar de a List<String>? O mejor aún, devuelva un Map<String,TheObjectType>con las claves que son los nombres y los valores de los objetos (a menos que sus objetos tengan un orden específico, en cuyo caso NavigableMappodría ser lo que desea.

Joachim Sauer
fuente
La razón para devolver la lista separada por comas es: si no creo la lista aquí, tendría que hacer esto en la persona que llama recorriendo los objetos (se necesita un valor CS). Quizás, estoy optimizando previamente innecesariamente.
Jagmal
2
Siempre me he preguntado por qué Java no tiene una clase Pair <T, U> por este motivo.
David Koelle el
Jagmal: sí, si el único rason para devolver la lista separada por comas es esta optimización, entonces olvídalo.
Joachim Sauer el
Esto solo funciona bien si los artículos que desea devolver son de la misma clase, o al menos tienen un ancestro común cercano. Quiero decir, usar Object en lugar de WhateverTypeYouWant no es muy bueno.
David Hanak el
@David: estoy de acuerdo en que usar Object aquí no es muy ordenado, pero luego devolver objetos sin ningún ancestro común (excepto Object, por supuesto) tampoco es muy ordenado. Incluso diría que es un olor a código, si lo necesitas.
Joachim Sauer el
69

Si sabe que va a devolver dos objetos, también puede usar un par genérico:

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;
    }
};

Editar Una implementación más completa de lo anterior:

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

    }

}

Notas, principalmente sobre la oxidación con Java y genéricos:

  • ambos ay bson inmutables.
  • makePairEl método estático lo ayuda a escribir la placa de la caldera, lo que el operador de diamantes en Java 7 hará menos molesto. Hay algo de trabajo para hacer que este re: genéricos sea realmente agradable, pero ahora debería estar bien. (cf PECS)
  • hashcodey equalsson generados por eclipse.
  • el tiempo de compilación del castmétodo está bien, pero no parece ser correcto.
  • No estoy seguro de si los comodines isInstanceson necesarios.
  • Acabo de escribir esto en respuesta a los comentarios, solo con fines ilustrativos.
David Hanak
fuente
Por lo general, tengo esta clase tocando en cada base de código en la que trabajo. También agregaría: una implementación hashCode / equals, y posiblemente un método isInstance () y cast () estático.
jamesh el
Claro, hay muchas maneras de hacer que esta clase sea más inteligente y más conveniente de usar. La versión anterior incluye lo que es suficiente en una declaración de una sola vez.
David Hanak el
@jamesh: ¿te importaría escribir tu par con todos los detalles aquí? Me gustaría saber cómo se ve después de suministrar "una implementación hashCode / equals, y posiblemente un método isInstance () y cast () estático". Gracias.
Qiang Li el
@QiangLi: generalmente genero el código hash y los métodos iguales. El método de instancia isInstance toma dos clases y se asegura de que a & b de la instancia sean instancias de esas clases. Cast toma un Par <?,?> Y lo lanza cuidadosamente a un Par <A, B>. Las implementaciones deberían ser bastante fáciles (sugerencia: Class.cast (), Class.isInstance ())
jamesh
2
Esa es una muy buena Pairimplementación. Un cambio menor que haría: agregar un mensaje al ClassCastException. De lo contrario, la depuración se convierte en una pesadilla si esto falla por alguna razón. (y las advertencias de supresión de los tipos sin formato serían innecesarias si se realiza la conversión Pair<?,?>(lo que funciona, porque solo necesita Objectmétodos de ay b). ¿Le importa si modifico el código?
Joachim Sauer
25

En el caso de que el método al que llama sea privado o se llame desde una ubicación, intente

return new Object[]{value1, value2};

La persona que llama se ve así:

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

El ejemplo Pair de David Hanak no tiene beneficio sintáctico y está limitado a dos valores.

return new Pair<Type1,Type2>(value1, value2);

Y la persona que llama se ve así:

Pair<Type1, Type2> temp=myMethod(parameters);
Type1 value1=temp.a;  //For code clarity: temp.a is not descriptive
Type2 value2=temp.b;
Kyle Lahnakoski
fuente
77
El par tiene un beneficio de control de tipo de clase
Hlex
55
En mi humilde opinión, no vayas por este camino: la declaración dice muy poco sobre los valores de retorno esperados. AFAIK, se prefiere más ampliamente crear clases genéricas que especifiquen cuántos parámetros se devuelven y el tipo de esos parámetros. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>, Etc. A continuación, un uso shows específicos del número y tipos de parámetros Pair<int, String> temp = ...o lo que sea.
ToolmakerSteve
22

Puede usar cualquiera de las siguientes formas:

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) Usando Array

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) Usando 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));
}

3) Usando 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));
}

4) Usando su clase de contenedor personalizado

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

5) Usando 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());
}

6) Usando Par de Apache Commons

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());
}
Viacheslav Vedenin
fuente
16

Casi siempre termino definiendo clases n-Tuple cuando codifico en Java. Por ejemplo:

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;}
}

Sé que es un poco feo, pero funciona, y solo tienes que definir tus tipos de tuplas una vez. Las tuplas son algo que Java realmente carece.

EDITAR: el ejemplo de David Hanak es más elegante, ya que evita definir getters y aún mantiene el objeto inmutable.

Ulrik Rasmussen
fuente
9

Antes de Java 5, estaría de acuerdo en que la solución Map no es ideal. No le daría una verificación de tipo de tiempo de compilación, por lo que puede causar problemas en tiempo de ejecución. Sin embargo, con Java 5, tenemos tipos genéricos.

Entonces su método podría verse así:

public Map<String, MyType> doStuff();

MyType, por supuesto, es el tipo de objeto que está devolviendo.

Básicamente, creo que devolver un Mapa es la solución correcta en este caso porque eso es exactamente lo que desea devolver: una asignación de una cadena a un objeto.

kipz
fuente
Esto no funcionará si alguno de los nombres choca. Una lista puede contener duplicados, pero un Mapa no puede (contener claves duplicadas).
tvanfosson
Por supuesto. Estaba haciendo suposiciones basadas en la pregunta, tal vez indebidamente :)
Kipz
Aunque su suposición es cierta en este caso, estoy entrando en el dominio de la optimización prematura (que no debería hacer).
Jagmal
6

Alternativamente, en situaciones en las que quiero devolver varias cosas de un método, a veces usaré un mecanismo de devolución de llamada en lugar de un contenedor. Esto funciona muy bien en situaciones en las que no puedo especificar con anticipación cuántos objetos se generarán.

Con su problema particular, se vería así:

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

fuente
perdón por comentar una respuesta muy antigua tuya, pero ¿cómo van las devoluciones de llamada con respecto a la recolección de basura? Ciertamente no tengo una buena comprensión de la gestión de la memoria java, si tiene objeto Allamado objeto B.getResult()y B.getResult()llamadas A.finishResult()como a callback, ¿el objeto Bse recolecta basura o permanece ahí hasta que A termine? ¡Probablemente sea una pregunta estúpida pero es una confusión fundamental que tengo!
wired00
6

Apache Commons tiene tuplas y triples para esto:

  • ImmutablePair<L,R> Un par inmutable que consta de dos elementos Object.
  • ImmutableTriple<L,M,R> Un triple inmutable que consta de tres elementos Object.
  • MutablePair<L,R> Un par mutable que consta de dos elementos Object.
  • MutableTriple<L,M,R> Un triple mutable que consta de tres elementos Object.
  • Pair<L,R> Un par que consta de dos elementos.
  • Triple<L,M,R> Un triple que consta de tres elementos.

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

jacob
fuente
6

Mientras que en su caso, el comentario puede ser una buena manera de hacerlo, en Android, puede usarlo Pair . Simplemente

return new Pair<>(yourList, yourCommaSeparatedValues);
serv-inc
fuente
5

Uso del siguiente objeto de entrada Ejemplo:

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

return new AbstractMap.simpleEntry<A,B>(instanceOfA,instanceOfB);
}
Sreeja Thummala
fuente
5

Con respecto al problema sobre los valores de retorno múltiples en general, generalmente uso una pequeña clase auxiliar que envuelve un solo valor de retorno y se pasa como parámetro al método:

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; }
}

(para los tipos de datos primitivos utilizo variaciones menores para almacenar directamente el valor)

Un método que quiera devolver múltiples valores se declararía de la siguiente manera:

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

Tal vez el principal inconveniente es que la persona que llama tiene que preparar los objetos devueltos por adelantado en caso de que quiera usarlos (y el método debe verificar si hay punteros nulos)

ReturnParameter<ClassA> nameForFirstValue = new ReturnParameter<ClassA>();
ReturnParameter<ClassB> nameForSecondValue = new ReturnParameter<ClassB>();
methodThatReturnsTwoValues(nameForFirstValue, nameForSecondValue);

Ventajas (en comparación con otras soluciones propuestas):

  • No tiene que crear una declaración de clase especial para métodos individuales y sus tipos de retorno
  • Los parámetros obtienen un nombre y, por lo tanto, son más fáciles de diferenciar al mirar la firma del método
  • Escriba seguridad para cada parámetro
koma
fuente
Gracias por una solución que proporciona seguridad de nombres y tipos a cada valor devuelto, sin requerir una declaración de clase por conjunto de tipos de valores devueltos.
ToolmakerSteve
3

Todas las posibles soluciones serán un kludge (como objetos de contenedor, su idea de HashMap, "valores de retorno múltiples" realizados a través de matrices). Recomiendo regenerar la lista separada por comas de la Lista devuelta. El código terminará siendo mucho más limpio.

Bombe
fuente
Estoy de acuerdo con usted en esto, pero si lo hago, terminaré dando vueltas dos veces (en realidad estoy creando los elementos de la lista uno por uno en el método existente).
Jagmal
1
@Jagmal: puede hacer un bucle dos veces, pero no importa la mayor parte del tiempo (vea la respuesta de artilugios).
Joachim Sauer el
1
Sí, no intentes optimizar tu código a menos que realmente tengas que hacerlo. Gizmo tiene mucha razón al respecto.
Bombe
3

Manténgalo simple y cree una clase para situaciones de resultados múltiples. Este ejemplo acepta una ArrayList y un mensaje de texto de una base de datos de ayuda getInfo.

Donde llama a la rutina que devuelve múltiples valores que codifica:

multResult res = mydb.getInfo(); 

En la rutina getInfo usted codifica:

ArrayList<String> list= new ArrayList<String>();
add values to the list...
return new multResult("the message", list);

y defina una clase multResult con:

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;
}

}

Martín
fuente
2

Desde mi punto de vista, hay realmente tres opciones aquí y la solución depende del contexto. Puede optar por implementar la construcción del nombre en el método que produce la lista. Esta es la elección que has elegido, pero no creo que sea la mejor. Está creando un acoplamiento en el método del productor con el método de consumo que no necesita existir. Es posible que otras personas que llaman no necesiten la información adicional y usted estaría calculando información adicional para estas personas que llaman.

Alternativamente, puede hacer que el método de llamada calcule el nombre. Si solo hay una persona que llama que necesita esta información, puede detenerse allí. No tiene dependencias adicionales y, aunque hay un pequeño cálculo adicional involucrado, ha evitado que su método de construcción sea demasiado específico. Esta es una buena compensación.

Por último, puede hacer que la lista misma sea responsable de crear el nombre. Esta es la ruta que seguiría si el cálculo debe ser realizado por más de una persona que llama. Creo que esto pone la responsabilidad de la creación de los nombres con la clase que está más estrechamente relacionada con los objetos mismos.

En el último caso, mi solución sería crear una clase de Lista especializada que devuelva una cadena separada por comas de los nombres de los objetos que contiene. Haga que la clase sea lo suficientemente inteligente como para que construya la cadena de nombre sobre la marcha a medida que se agregan y eliminan objetos. Luego, devuelva una instancia de esta lista y llame al método de generación de nombres según sea necesario. Aunque puede ser casi tan eficiente (y más simple) simplemente retrasar el cálculo de los nombres hasta la primera vez que se llama al método y almacenarlo luego (carga diferida). Si agrega / elimina un objeto, solo necesita eliminar el valor calculado y hacer que se vuelva a calcular en la próxima llamada.

tvanfosson
fuente
2

Puede hacer algo como una tupla en lenguaje dinámico (Python)

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]);
}
}

y usar así

public Tuple returnMultiValues(){
   return Tuple._t(new ArrayList(),new HashMap())
}


Tuple t = returnMultiValues();
ArrayList list = t.at(0,ArrayList.class);
Deva
fuente
2

Seguí un enfoque similar al descrito en las otras respuestas con algunos ajustes basados ​​en el requisito que tenía, básicamente creé las siguientes clases (por si acaso, todo es Java):

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

Entonces, mi requisito era simple, en la clase de repositorio que llega a la base de datos, para obtener métodos que recuperar datos de la base de datos, necesito verificar si falló o tuvo éxito, luego, si tenía éxito, necesitaba jugar con la lista de retorno , si falla, detenga la ejecución y notifique el error.

Entonces, por ejemplo, mis métodos son así:

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
}

Donde ResultMessage es solo una clase con dos campos (código / mensaje) y Customer es cualquier clase con un montón de campos que provienen de la base de datos.

Luego, para verificar el resultado, solo hago esto:

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!");
    }
}
Marco Vargas
fuente
1

En C ++ (STL) hay una clase de pares para agrupar dos objetos. En Java Generics, una clase de pares no está disponible, aunque existe cierta demanda . Sin embargo, podría implementarlo usted mismo fácilmente.

Sin embargo, estoy de acuerdo con algunas otras respuestas que si necesita devolver dos o más objetos de un método, sería mejor encapsularlos en una clase.

kgiannakakis
fuente
1

¿Por qué no crear un WhateverFunctionResultobjeto que contenga sus resultados y la lógica necesaria para analizar estos resultados, repetirlos, etc.? Me parece que tampoco:

  1. Estos objetos de resultados están íntimamente unidos / relacionados y pertenecen juntos, o:
  2. no están relacionados, en cuyo caso su función no está bien definida en términos de lo que está tratando de hacer (es decir, hacer dos cosas diferentes)

Veo este tipo de problemas surgir una y otra vez. No tenga miedo de crear sus propias clases de contenedor / resultado que contengan los datos y la funcionalidad asociada para manejar esto. Si simplemente pasa las cosas en una HashMapo similar, entonces sus clientes tienen que separar este mapa y asimilar el contenido cada vez que quieran usar los resultados.

Brian Agnew
fuente
Debido a que es una PITA tener que definir una clase cada vez que necesita devolver múltiples valores, simplemente porque el lenguaje carece de esta característica comúnmente útil;) Pero en serio, lo que sugiere es muy valioso.
ToolmakerSteve
1
public class MultipleReturnValues {

    public MultipleReturnValues() {
    }

    public static void functionWithSeveralReturnValues(final String[] returnValues) {
        returnValues[0] = "return value 1";
        returnValues[1] = "return value 2";
    }

    public static void main(String[] args) {
        String[] returnValues = new String[2];
        functionWithSeveralReturnValues(returnValues);
        System.out.println("returnValues[0] = " + returnValues[0]);
        System.out.println("returnValues[1] = " + returnValues[1]);
    }

}
tsug303
fuente
1

Esto no responde exactamente la pregunta, pero dado que cada una de las soluciones dadas aquí tiene algunos inconvenientes, le sugiero que intente refactorizar su código un poco, por lo que debe devolver solo un valor.

Caso uno.

Necesita algo dentro y fuera de su método. ¿Por qué no calcularlo afuera y pasarlo al método?

En vez de:

[thingA, thingB] = createThings(...);  // just a conceptual syntax of method returning two values, not valid in Java

Tratar:

thingA = createThingA(...);
thingB = createThingB(thingA, ...);

Esto debería cubrir la mayoría de sus necesidades, ya que en la mayoría de las situaciones se crea un valor antes que el otro y puede dividirlo creando dos métodos. El inconveniente es que el método createThingsBtiene un parámetro adicional en comparación createThings, y posiblemente esté pasando exactamente la misma lista de parámetros dos veces a diferentes métodos.


Caso dos.

La solución más obvia y una versión simplificada del caso uno. No siempre es posible, pero ¿quizás ambos valores se puedan crear independientemente uno del otro?

En vez de:

[thingA, thingB] = createThings(...);  // see above

Tratar:

thingA = createThingA(...);
thingB = createThingB(...);

Para hacerlo más útil, estos dos métodos pueden compartir una lógica común:

public ThingA createThingA(...) {
    doCommonThings(); // common logic
    // create thing A
}
public ThingB createThingB(...) {
    doCommonThings(); // common logic
    // create thing B
}
X. Wo Satuk
fuente
0

Pase una lista a su método y complétela, luego devuelva la Cadena con los nombres, así:

public String buildList(List<?> list) {
    list.add(1);
    list.add(2);
    list.add(3);
    return "something,something,something,dark side";
}

Entonces llámalo así:

List<?> values = new ArrayList<?>();
String names = buildList(values);
Triqui
fuente
-2

He estado usando un enfoque muy básico para lidiar con problemas de retornos múltiples. Cumple el propósito y evita la complejidad.

Lo llamo el enfoque separador de cadenas

Y es eficaz, ya que incluso puede devolver valores de tipos múltiples, por ejemplo, int, double, char, string, etc.

En este enfoque, usamos una cadena que es muy poco probable que ocurra en general. Lo llamamos como un separador. Este separador se usaría para separar varios valores cuando se usa en una función

Por ejemplo, tendremos nuestro retorno final como (por ejemplo) separador intValue separador doubleValue ... Y luego, usando esta cadena, recuperaremos toda la información requerida, que también puede ser de diferentes tipos.

El siguiente código mostrará el funcionamiento de este concepto.

El separador utilizado es ! @ # Y se devuelven 3 valores intVal, doubleVal y stringVal

        public class TestMultipleReturns {

            public static String multipleVals() {

                String result = "";
                String separator = "!@#";


                int intVal = 5;
                // Code to process intVal

                double doubleVal = 3.14;
                // Code to process doubleVal

                String stringVal = "hello";
                // Code to process Int intVal

                result = intVal + separator + doubleVal + separator + stringVal + separator;
                return (result);
            }

            public static void main(String[] args) {

                String res = multipleVals();

                int intVal = Integer.parseInt(res.split("!@#")[0]);
                // Code to process intVal

                double doubleVal = Double.parseDouble(res.split("!@#")[1]);
                // Code to process doubleVal

                String stringVal = res.split("!@#")[2];

                System.out.println(intVal+"\n"+doubleVal+"\n"+stringVal);
            }
        }

SALIDA

5
3.14
hello
BUILD SUCCESSFUL (total time: 2 seconds)
Jay Dharmendra Solanki
fuente
3
yuk Enorme código de olor. Análisis, en lugar de utilizar las funciones orientadas a objetos disponibles. OMI, uno de los peores ejemplos de codificación que he visto. A menos que esté describiendo una situación en la que necesite pasar múltiples valores entre dos programas independientes u otra comunicación entre procesos, y de alguna manera no tenga acceso a un mecanismo decente para hacerlo (json u otro).
ToolmakerSteve
-4

En C, lo haría pasando punteros a marcadores de posición para los resultados como argumentos:

void getShoeAndWaistSizes(int *shoeSize, int *waistSize) {
    *shoeSize = 36;
    *waistSize = 45;
}
...
int shoeSize, waistSize;
getShoeAndWaistSize(&shoeSize, &waistSize);
int i = shoeSize + waistSize;

Probemos algo similar, en Java.

void getShoeAndWaistSizes(List<Integer> shoeSize, List<Integer> waistSize) {
    shoeSize.add(36);
    waistSize.add(45);
}
...
List<Integer> shoeSize = new List<>();
List<Integer> waistSize = new List<>();
getShoeAndWaistSizes(shoeSize, waistSize);
int i = shoeSize.get(0) + waistSize.get(0);
Adrian Panasiuk
fuente
1
Sin embargo, en un lenguaje OO, generalmente se considera preferible hacer lo que varias personas ya sugirieron cuatro años antes de esta respuesta: agrupar los dos valores relacionados en un objeto (par, tupla o definición de clase personalizada), y luego tener una lista de esos objetos. Hacerlo evita la necesidad de pasar varias listas. Esto se vuelve especialmente importante si es necesario pasar dicho par (un elemento de cada una de sus listas) a otros métodos, para su posterior procesamiento.
ToolmakerSteve
@ToolmakerSteve Para aclarar: las listas están destinadas a tener exactamente un elemento cada una y son solo un medio para implementar un análogo al paso por puntero. No están destinados a recopilar varios resultados, o incluso a usarse más allá de un par de líneas después de la llamada al método.
Adrian Panasiuk
-5

PASAR UN HASH EN EL MÉTODO Y POBLARLO ......

public Void buildResponse (datos de cadena, respuesta de mapa);

l_39217_l
fuente