Como são retornados vários valores em Java?

11

Às vezes, você deseja retornar vários valores de uma função. Como isso é feito normalmente em Java?

Uma opção é usar uma matriz, como este trecho de código Python que retorna uma lista ou tupla:

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

Outra opção seria retornar um hash / dict, como este exemplo de JavaScript:

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

Mais um seria criar um objeto personalizado apenas para esse fim, como este exemplo de Java:

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

É claro que você também pode usar algumas variáveis ​​globais para armazenar o que precisa, em vez de repassar as coisas, mas digamos que não é uma opção.

Mike M. Lin
fonte
As pessoas Java "reais" realmente enfrentam o problema de usar getters e setters públicos para ocultar campos em pequenas classes internas como essa? Apenas curioso.
Chris Farmer
3
Sim, a maioria faz. Como muitas estruturas esperam o padrão JavaBean, você pode se arrepender de não ter getters e setters. De qualquer forma, seu IDE irá gerá-los para você.
Eric Wilson
3
Ou você pode simplesmente deixá-los de fora, com base no princípio YAGNI. Mas isso não parece acontecer com a frequência esperada.
MatrixFrog
@ Farmacoy: Eu acho que entendo para beans e afins, mas o OP implica que esta é apenas uma classe única projetada para retornar vários valores.
25711 Chris Farmer
@ ChrisFarmer Acho que, com esse contexto, nunca vi um programador Java 'real' criar uma classe para esse fim.
Eric Wilson

Respostas:

26

Como isso é feito normalmente em Java?

Dolorosamente.

Uma opção é usar uma matriz, como este trecho de código Python que retorna uma lista ou tupla ...

Outra opção seria retornar um hash / dict, como este exemplo de JavaScript ...

Essas técnicas não funcionam bem em Java; os valores teriam que ser baixados do objeto.

Mais um seria criar um objeto personalizado apenas para esse fim, como este exemplo de Java ...

Isso é mais comum, mas é tedioso criar todas essas pequenas classes. Em C ++, é comum usar std :: pair, mas isso geralmente não é feito em Java.

Com o Lombok , é muito fácil criar pequenos objetos personalizados:

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

}

Kevin Cline
fonte
10
"Como isso é feito normalmente em Java?" "Dolorosamente." lol como um desenvolvedor Java que eu tenho que +1-lo por isso
TheLQ
Usando um compacto imutável struct-como classe não é tão doloroso ... É realmente como escrever um struct C ...
Guillaume
1
@ Guillaume - claro, mas todas essas pequenas coisas se somam no tempo e no espaço. Não sei por que a comunidade Java não adotou um conjunto padrão de genéricos como "classe Par <T1, T2> {public T1 first; public T2 second; ...}"; nas línguas modernas você apenas "retorna a, b"; e escreva "x, y = f ()";
Kevin cline
1
Tenho certeza de que uma linguagem 'antiga' também é capaz de fazê-lo :) IMHO Encontrei vários valores de retorno que podem levar à bagunça total e, se você precisar adicionar outros campos de retorno, basta atualizar sua estrutura como a classe sem precisar altere sua assinatura de método.
Guillaume
1
Isso "dolorosamente". me impressionou, sim, é exatamente o que eu sinto como desenvolvedor Java quando encontro situações semelhantes.
Artjom # 25/13
13

Sim, a maneira de criar um struct/ tuple/ recordem Java é criando uma classe. Se for apenas para uso interno, prefiro usar uma pequena classe imutável de estrutura com campos públicos.

Exemplos:

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

Isso é muito mais fácil de fazer no Scala:

case class Unreliably(success: Boolean, value: Int)
Jonas
fonte
8
Na verdade, em Scala, você provavelmente provavelmente retornaria a Tuple2[Boolean, Int]. Embora neste exemplo específico , você retorne um Option[Int].
Jörg W Mittag
2
Portanto, isso responde à pergunta de Chris Farmer (nos comentários do Q) de que pessoas reais de Java não criam necessariamente getters e setters para pequenas classes internas. Você é uma pessoa Java "real", certo?
Mike M. Lin
2
Em outras notícias, não existem escoceses verdadeiros.
Joseph Weissman
5

Para o exemplo que você deu, lançar uma exceção seria a maneira mais padrão de lidar com isso:

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

Além disso, se você se esforçar para ter funções que "realizem uma coisa", o recurso de retornar vários valores é menos necessário, embora ocasionalmente conveniente.

Eric Wilson
fonte
4

Temos uma classe genérica Pair que pode armazenar uma instância de A e uma instância de B. Você provavelmente pode criar um Tripleto ou Quádruplo da mesma maneira.

public class Pair<A, B>
{
    ...
}
Raku
fonte
1
isso cria um código REALMENTE ilegível. se um método retornar Pair<String, Integer>, o que isso significa? o que esses valores representam? você não pode saber sem ler a implementação do método.
Sara
1

Em Java, sua função retornaria um objeto (ou talvez nulo no caso de uma falha). Dessa forma, vários dados podem ser retornados.

Scott C Wilson
fonte
1

Não há uma maneira explícita de retornar várias variáveis ​​em Java, no entanto, existem algumas abordagens:

  1. O primeiro é seguir o caminho da matriz. Isso realmente funciona se você tiver tudo como o mesmo tipo de dados ou se puder convertê-los temporariamente em um tipo.
  2. A segunda maneira é criar uma classe com a finalidade de transferir vários tipos de variáveis. No meu trabalho, nos referimos a eles como DTOs ou Data Transfer Objects.

fonte