¿Cómo se devuelven múltiples valores en Java?

11

A veces desea devolver múltiples valores de una función. ¿Cómo se hace esto normalmente en Java?

Una opción es usar una matriz, como este fragmento de Python que devuelve una lista o tupla:

value, success = read_unreliably()
if success:
    print value

Otra opción sería devolver un hash / dict, como este ejemplo de JavaScript:

var result = readUnreliably()
if (result.success) {
    alert(value);
}

Una más sería crear un objeto personalizado solo para este propósito, como este ejemplo de Java:

ReadUnreliablyResult result = readUnreliably()
if (result.getSuccess()) {
    System.out.println(result.getValue());
}

Por supuesto, también puede usar algunas variables globales para almacenar lo que necesita en lugar de pasar las cosas, pero digamos que no es una opción.

Mike M. Lin
fuente
¿La gente java "real" realmente pasa por la molestia de usar captadores y establecedores públicos para ocultar campos en pequeñas clases internas como esa? Sólo curioso.
Chris Farmer
3
Sí, la mayoría lo hace. Dado que muchos marcos esperan el estándar JavaBean, puede lamentar no tener getters y setters. En cualquier caso, su IDE los generará por usted.
Eric Wilson
3
O simplemente puede dejarlos fuera, según el principio YAGNI. Pero eso no parece suceder tan a menudo como cabría esperar.
MatrixFrog
@FarmBoy: Creo que entiendo los beans y tal, pero el OP implica que esta es solo una clase única diseñada para devolver múltiples valores.
Chris Farmer
@ChrisFarmer Supongo que con ese contexto, nunca he visto a un programador Java 'real' crear una clase para este propósito.
Eric Wilson

Respuestas:

26

¿Cómo se hace esto normalmente en Java?

Penosamente.

Una opción es usar una matriz, como este fragmento de Python que devuelve una lista o tupla ...

Otra opción sería devolver un hash / dict, como este ejemplo de JavaScript ...

Estas técnicas no funcionan bien en Java; los valores tendrían que ser downcast de Object.

Una más sería crear un objeto personalizado solo para este propósito, como este ejemplo de Java ...

Esto es más común, pero es tedioso crear todas esas pequeñas clases. En C ++ es común usar std :: pair pero esto no se hace comúnmente en Java.

Con Lombok es bastante fácil crear pequeños objetos personalizados:

@RequiredArgsConstructor
public class X {
  private final boolean status;
  private final byte[] data;

}

Kevin Cline
fuente
10
"¿Cómo se hace esto normalmente en Java?" "Penosamente." lol como desarrollador de Java tengo que hacer +1 para eso
TheLQ
Usar una clase compacta de estructura inmutable no es tan doloroso ... Es realmente como escribir una estructura C ...
Guillaume
1
@Guillaume: claro, pero todas esas pequeñas cosas se suman tanto en tiempo como en espacio. No sé por qué la comunidad Java no ha adoptado un conjunto estándar de genéricos como "class Pair <T1, T2> {public T1 first; public T2 second; ...}"; en idiomas modernos simplemente "devuelve a, b"; y luego escribe "x, y = f ()";
Kevin Cline
1
Estoy seguro de que algún lenguaje 'antiguo' también puede hacerlo :) En mi humilde opinión, encontré que múltiples valores de retorno pueden conducir a un desorden total, y si necesita agregar otros campos de retorno, solo tiene que actualizar su estructura como clase sin Cambia la firma de tu método.
Guillaume
1
Eso "dolorosamente". me golpeó duro, sí, es exactamente lo que siento como desarrollador de Java cuando me encuentro con situaciones similares.
artjom
13

Sí, la forma de crear un struct/ tuple/ recorden Java es creando una clase. Si es solo para uso interno, prefiero usar una pequeña clase de estructura inmutable con campos públicos.

Ejemplos:

public class Unreliably {
    public final boolean success;
    public final int value;
    public Unreliably(boolean success, int value) {
        this.success = success; this.value = value;
    }
}

Esto es mucho más fácil de hacer en Scala:

case class Unreliably(success: Boolean, value: Int)
Jonas
fuente
8
En realidad, en Scala, probablemente solo devolverías a Tuple2[Boolean, Int]. Aunque en este ejemplo específico , devolvería un Option[Int].
Jörg W Mittag
2
Así que esto responde a la pregunta de Chris Farmer (en los comentarios de la Q) de que la gente real de Java no necesariamente crea captadores y establecedores para pequeñas clases internas. Eres una persona Java "real", ¿verdad?
Mike M. Lin
2
En otras noticias, no hay verdaderos escoceses.
Joseph Weissman
5

Para el ejemplo que ha dado, lanzar una excepción sería la forma más estándar de manejarlo:

try {
    result = readUnreliably();
    System.out.println(result);
} (catch IOException e) {
    System.out.println("Could not read file");
}

Además, si se esfuerza por tener funciones que "hagan una cosa", la característica de devolver múltiples valores es menos necesaria, aunque en ocasiones conveniente.

Eric Wilson
fuente
4

Tenemos una clase genérica Par que puede almacenar una instancia de A y una instancia de B. Probablemente pueda crear un Triplete o Quadruplet de la misma manera.

public class Pair<A, B>
{
    ...
}
Raku
fuente
1
Sin embargo, esto genera un código REALMENTE ilegible. si un método regresa Pair<String, Integer>, ¿qué significa eso? ¿Qué representan estos valores? no puede saberlo sin leer la implementación del método.
sara
1

En Java, su función devolvería un objeto (o quizás nulo en el caso de una falla). De esta manera, se pueden devolver múltiples datos.

Scott C Wilson
fuente
1

No hay una forma explícita de devolver múltiples variables en Java, sin embargo, hay algunos enfoques:

  1. El primero es seguir el camino de la matriz. Esto solo funciona si tiene todo como el mismo tipo de datos o puede convertirlos temporalmente a un tipo.
  2. La segunda forma es crear una clase con el propósito de transferir múltiples tipos de variables. En mi trabajo nos referimos a estos como DTO u objetos de transferencia de datos.

fuente