Comment renvoyer plusieurs objets à partir d'une méthode Java?


173

Je souhaite renvoyer deux objets à partir d'une méthode Java et je me demandais quelle pourrait être une bonne façon de le faire?

Les moyens possibles auxquels je peux penser sont: renvoyer un HashMap(puisque les deux objets sont liés) ou renvoyer un ArrayListdes Objectobjets.

Pour être plus précis, les deux objets que je veux retourner sont (a) Listdes objets et (b) des noms séparés par des virgules.

Je veux renvoyer ces deux objets à partir d'une méthode car je ne veux pas parcourir la liste des objets pour obtenir les noms séparés par des virgules (ce que je peux faire dans la même boucle dans cette méthode).

D'une manière ou d'une autre, renvoyer un HashMapne semble pas être une manière très élégante de le faire.


1
La liste et les CSV ont-ils des vues fondamentalement différentes des mêmes données? Cela ressemble à ce dont vous avez besoin est un objet où vous avez une seule Listréférence et une sorte de table de recherche.
James P.

Réponses:


128

Si vous souhaitez renvoyer deux objets, vous souhaitez généralement renvoyer un seul objet qui encapsule les deux objets à la place.

Vous pouvez renvoyer une liste d' NamedObjectobjets comme ceci:

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

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

Ensuite, vous pouvez facilement retourner un fichier List<NamedObject<WhateverTypeYouWant>>.

Aussi: Pourquoi voudriez-vous renvoyer une liste de noms séparés par des virgules au lieu d'un List<String>? Ou mieux encore, retournez a Map<String,TheObjectType>avec les clés étant les noms et les valeurs des objets (sauf si vos objets ont spécifié un ordre, auquel cas a NavigableMappeut être ce que vous voulez.


La raison du renvoi de la liste séparée par des virgules est la suivante: si je ne crée pas la liste ici, je devrais le faire dans l'appelant en boucle sur les objets (la valeur CS est nécessaire). Peut-être que je pré-optimise inutilement.
Jagmal

2
Je me suis toujours demandé pourquoi Java n'avait pas de classe Pair <T, U> pour cette raison.
David Koelle

Jagmal: oui, si le seul rason pour renvoyer la liste séparée par des virgules est cette optimisation, alors oubliez-la.
Joachim Sauer le

Cela ne fonctionne bien que si les éléments que vous souhaitez renvoyer sont de la même classe ou ont au moins un ancêtre commun proche. Je veux dire, utiliser Object à la place de WhateverTypeYouWant n'est pas très soigné.
David Hanak

@David: Je suis d'accord qu'utiliser Object ici n'est pas très soigné, mais encore une fois, renvoyer des objets sans ancêtre commun (sauf Object bien sûr) n'est pas non plus très soigné. Je dirais même que c'est une odeur de code, si vous en avez besoin.
Joachim Sauer le

69

Si vous savez que vous allez renvoyer deux objets, vous pouvez également utiliser une paire générique:

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

Edit Une implémentation plus complète de ce qui précède:

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

    }

}

Remarques, principalement sur la rouille avec Java et les génériques:

  • les deux aet bsont immuables.
  • makePairLa méthode statique vous aide à saisir la plaque de chaudière, ce que l'opérateur diamant de Java 7 rendra moins ennuyeux. Il y a du travail pour rendre ce re: génériques vraiment sympa, mais ça devrait être ok-ish maintenant. (cf PECS)
  • hashcodeet equalssont générés par éclipse.
  • le temps de compilation dans la castméthode est correct, mais ne semble pas tout à fait correct.
  • Je ne suis pas sûr que les caractères génériques isInstancesoient nécessaires.
  • Je viens d'écrire ceci en réponse aux commentaires, à des fins d'illustration uniquement.

J'ai généralement cette classe dans chaque code de base sur lequel je travaille. J'ajouterais également: une implémentation hashCode / equals, et éventuellement une méthode statique isInstance () et cast ().
jamesh

Bien sûr, il existe de nombreuses façons de rendre cette classe plus intelligente et plus pratique à utiliser. La version ci-dessus inclut ce qui est juste assez dans une déclaration one-shot.
David Hanak

@jamesh: cela vous dérange-t-il d'écrire votre paire en détail ici? Je voudrais savoir à quoi cela ressemble après avoir fourni "une implémentation hashCode / equals, et éventuellement une méthode statique isInstance () et cast ()". Je vous remercie.
Qiang Li

@QiangLi - Je génère généralement les méthodes hashcode & equals. La méthode d'instance isInstance prend deux classes et s'assure que les instances a et b sont des instances de ces classes. Le lancer prend une paire <?,?> Et la lance soigneusement en une paire <A, B>. Les implémentations devraient être assez faciles (indice: Class.cast (), Class.isInstance ())
jamesh

2
C'est une très belle Pairimplémentation. Un changement mineur que je ferais: ajouter un message au ClassCastException. Sinon, le débogage devient un cauchemar si cela échoue pour une raison quelconque. (et les rawtypes suppress-warnings seraient inutiles si vous faisiez un cast vers Pair<?,?>(ce qui fonctionne, car vous n'avez besoin que de Objectméthodes de aet b). Cela vous dérange-t-il si je modifie le code?
Joachim Sauer

25

Dans le cas où la méthode que vous appelez est privée ou appelée à partir d'un emplacement, essayez

return new Object[]{value1, value2};

L'appelant ressemble à:

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

L'exemple Pair de David Hanak n'a aucun avantage syntaxique et est limité à deux valeurs.

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

Et l'appelant ressemble à:

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

7
Paire a l'avantage de contrôle de type de classe
Hlex

5
À mon humble avis, n'allez pas dans cette direction - la déclaration en dit trop peu sur les valeurs de retour attendues. AFAIK, il est plus largement préférable de créer des classes génériques qui spécifient le nombre de paramètres renvoyés et le type de ces paramètres. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>, Etc. Ensuite , une utilisation spécifique indique le nombre et les types de paramètres Pair<int, String> temp = ...ou autre chose.
ToolmakerSteve

22

Vous pouvez utiliser l'une des méthodes suivantes:

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) Utilisation de la matrice

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) Utilisation de 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) Utilisation de 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) Utilisation de votre classe de conteneur personnalisée

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) Utilisation de 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) Utilisation d'une paire d' 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());
}

16

Je finis presque toujours par définir des classes n-Tuple lorsque je code en Java. Par exemple:

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

Je sais que c'est un peu moche, mais cela fonctionne, et il vous suffit de définir vos types de tuple une fois. Les tuples sont quelque chose qui manque vraiment à Java.

EDIT: L'exemple de David Hanak est plus élégant, car il évite de définir des getters et garde toujours l'objet immuable.


9

Avant Java 5, je conviendrais en quelque sorte que la solution Map n'est pas idéale. Cela ne vous donnerait pas la vérification du type au moment de la compilation et pourrait donc causer des problèmes lors de l'exécution. Cependant, avec Java 5, nous avons des types génériques.

Votre méthode pourrait donc ressembler à ceci:

public Map<String, MyType> doStuff();

MyType étant bien sûr le type d'objet que vous renvoyez.

Fondamentalement, je pense que renvoyer une carte est la bonne solution dans ce cas, car c'est exactement ce que vous voulez retourner - un mappage d'une chaîne sur un objet.


Cela ne fonctionnera pas si l'un des noms entre en collision. Une liste peut contenir des doublons, mais une carte ne peut pas (contenir des clés en double).
tvanfosson le

Bien sûr. Je faisais des hypothèses basées sur la question - peut-être indûment :)
kipz

Bien que votre hypothèse soit vraie dans ce cas, j'entre dans le domaine de l'optimisation prématurée (ce que je ne devrais pas faire).
Jagmal

6

Alternativement, dans les situations où je veux retourner un certain nombre de choses à partir d'une méthode, j'utiliserai parfois un mécanisme de rappel au lieu d'un conteneur. Cela fonctionne très bien dans les situations où je ne peux pas spécifier à l'avance combien d'objets seront générés.

Avec votre problème particulier, cela ressemblerait à ceci:

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

désolé d'avoir commenté une très ancienne réponse, mais comment se passent les rappels concernant le ramasse-miettes? Je n'ai certainement pas une bonne compréhension de la gestion de la mémoire dans java, si vous avez un objet d' Aappel d'objet B.getResult()et des B.getResult()appels en A.finishResult()tant que callback, l'objet Best-il ramassé ou reste-t-il jusqu'à ce que A se termine? probablement une question stupide mais c'est une confusion fondamentale que j'ai!
filaire 00

6

Apache Commons a un tuple et un triple pour cela:

  • ImmutablePair<L,R> Une paire immuable composée de deux éléments Object.
  • ImmutableTriple<L,M,R> Un triple immuable composé de trois éléments Object.
  • MutablePair<L,R> Une paire mutable composée de deux éléments Object.
  • MutableTriple<L,M,R> Un triple mutable composé de trois éléments Object.
  • Pair<L,R> Une paire composée de deux éléments.
  • Triple<L,M,R> Un triple composé de trois éléments.

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


6

Alors que dans votre cas, le commentaire peut être un bon moyen de procéder, sous Android, vous pouvez l'utiliser Pair . Simplement

return new Pair<>(yourList, yourCommaSeparatedValues);

5

Utilisation de l'objet Entry suivant Exemple:

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

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

5

En ce qui concerne le problème des valeurs de retour multiples en général, j'utilise généralement une petite classe d'assistance qui encapsule une seule valeur de retour et est passée en paramètre à la méthode:

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

(pour les types de données primitifs, j'utilise des variations mineures pour stocker directement la valeur)

Une méthode qui veut retourner plusieurs valeurs serait alors déclarée comme suit:

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

Peut-être que le principal inconvénient est que l'appelant doit préparer les objets de retour à l'avance au cas où il voudrait les utiliser (et la méthode devrait vérifier les pointeurs nuls)

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

Avantages (par rapport aux autres solutions proposées):

  • Vous n'avez pas besoin de créer une déclaration de classe spéciale pour les méthodes individuelles et ses types de retour
  • Les paramètres ont un nom et sont donc plus faciles à différencier lorsque l'on regarde la signature de la méthode
  • Type de sécurité pour chaque paramètre

Merci pour une solution qui donne des noms et une sécurité de type à chaque valeur renvoyée, sans nécessiter de déclaration de classe par ensemble de types de valeur renvoyés.
ToolmakerSteve

3

Toutes les solutions possibles seront un kludge (comme les objets conteneurs, votre idée HashMap, «plusieurs valeurs de retour» telles que réalisées via des tableaux). Je recommande de régénérer la liste séparée par des virgules de la liste retournée. Le code finira par être beaucoup plus propre.


Je suis d'accord avec vous sur ce point, mais si je le fais, je finirai par boucler deux fois (je crée en fait les éléments de la liste un par un dans la méthode existante).
Jagmal

1
@Jagmal: vous pouvez boucler deux fois, mais cela n'a pas d'importance la plupart du temps (voir la réponse aux gadgets).
Joachim Sauer

1
Ouais, n'essayez pas d'optimiser votre code à moins que ce ne soit vraiment nécessaire. gizmo a tout à fait raison à ce sujet.
Bombe

3

Restez simple et créez une classe pour une situation à résultats multiples. Cet exemple accepte une ArrayList et un texte de message à partir d'un databasehelper getInfo.

Où vous appelez la routine qui renvoie plusieurs valeurs que vous codez:

multResult res = mydb.getInfo(); 

Dans la routine getInfo vous codez:

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

et définissez une classe multResult avec:

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

}


2

Selon moi, il y a vraiment trois choix ici et la solution dépend du contexte. Vous pouvez choisir d'implémenter la construction du nom dans la méthode qui produit la liste. C'est le choix que vous avez choisi, mais je ne pense pas que ce soit le meilleur. Vous créez un couplage dans la méthode du producteur avec la méthode de consommation qui n'a pas besoin d'exister. D'autres appelants peuvent ne pas avoir besoin des informations supplémentaires et vous calculeriez des informations supplémentaires pour ces appelants.

Vous pouvez également demander à la méthode appelante de calculer le nom. Si un seul appelant a besoin de ces informations, vous pouvez vous arrêter là. Vous n'avez pas de dépendances supplémentaires et bien qu'il y ait un petit calcul supplémentaire impliqué, vous avez évité de rendre votre méthode de construction trop spécifique. C'est un bon compromis.

Enfin, vous pourriez avoir la liste elle-même responsable de la création du nom. C'est l'itinéraire que j'irais si le calcul doit être effectué par plus d'un appelant. Je pense que cela confère la responsabilité de la création des noms à la classe la plus étroitement liée aux objets eux-mêmes.

Dans ce dernier cas, ma solution serait de créer une classe List spécialisée qui renvoie une chaîne séparée par des virgules des noms des objets qu'elle contient. Rendez la classe suffisamment intelligente pour qu'elle construise la chaîne de nom à la volée au fur et à mesure que des objets y sont ajoutés et supprimés. Ensuite, retournez une instance de cette liste et appelez la méthode de génération de nom si nécessaire. Bien qu'il puisse être presque aussi efficace (et plus simple) de simplement retarder le calcul des noms jusqu'au premier appel de la méthode et de le stocker ensuite (chargement différé). Si vous ajoutez / supprimez un objet, il vous suffit de supprimer la valeur calculée et de la recalculer lors du prochain appel.


2

Peut faire quelque chose comme un tuple en langage dynamique (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]);
}
}

et utiliser comme ça

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


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

2

J'ai suivi une approche similaire à celle décrite dans les autres réponses avec quelques ajustements basés sur l'exigence que j'avais, en gros, j'ai créé les classes suivantes (juste au cas où, tout est 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);
    }
}

Ensuite, mon exigence était simple, dans la classe de référentiel qui atteint la base de données, pour les méthodes Get que de récupérer des données de la base de données, je dois vérifier si cela a échoué ou réussi, puis, en cas de succès, je devais jouer avec la liste de retour , en cas d'échec, arrêtez l'exécution et notifiez l'erreur.

Ainsi, par exemple, mes méthodes sont comme ceci:

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
}

Où ResultMessage est juste une classe avec deux champs (code / message) et Customer est n'importe quelle classe avec un tas de champs provenant de la base de données.

Ensuite, pour vérifier le résultat, je fais juste ceci:

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

1

En C ++ (STL), il existe une classe de paires pour regrouper deux objets. Dans Java Generics, une classe de paires n'est pas disponible, bien qu'il y ait une certaine demande . Cependant, vous pouvez facilement l'implémenter vous-même.

Je suis cependant d'accord avec certaines autres réponses que si vous devez renvoyer deux objets ou plus à partir d'une méthode, il serait préférable de les encapsuler dans une classe.


1

Pourquoi ne pas créer un WhateverFunctionResultobjet contenant vos résultats, et la logique nécessaire pour analyser ces résultats, itérer ensuite etc. Il me semble que soit:

  1. Ces objets de résultats sont intimement liés entre eux / liés et appartiennent ensemble, ou:
  2. ils ne sont pas liés, auquel cas votre fonction n'est pas bien définie en termes de ce qu'elle essaie de faire (c.-à-d. faire deux choses différentes)

Je vois ce genre de problème surgir encore et encore. N'ayez pas peur de créer vos propres classes de conteneur / résultat contenant les données et les fonctionnalités associées pour gérer cela. Si vous faites simplement passer les choses dans un HashMapou similaire, vos clients doivent séparer cette carte et en groover le contenu chaque fois qu'ils veulent utiliser les résultats.


Parce que c'est un PITA d'avoir à définir une classe chaque fois que vous avez besoin de renvoyer plusieurs valeurs, simplement parce que le langage ne dispose pas de cette fonctionnalité couramment utile;) Mais sérieusement, ce que vous suggérez vaut très souvent la peine d'être fait.
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]);
    }

}

1

Cela ne répond pas exactement à la question, mais comme chacune des solutions présentées ici présente des inconvénients, je suggère d'essayer de refactoriser un peu votre code afin que vous n'ayez à renvoyer qu'une seule valeur.

Cas un.

Vous avez besoin de quelque chose à l'intérieur comme à l'extérieur de votre méthode. Pourquoi ne pas le calculer à l'extérieur et le passer à la méthode?

Au lieu de:

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

Essayer:

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

Cela devrait couvrir la plupart de vos besoins, car dans la plupart des situations, une valeur est créée avant l'autre et vous pouvez les séparer en deux méthodes. L'inconvénient est que la méthode createThingsBa un paramètre supplémentaire par rapport à createThings, et peut-être que vous passez exactement la même liste de paramètres deux fois à différentes méthodes.


Cas deux.

La solution la plus évidente jamais réalisée et une version simplifiée du cas un. Ce n'est pas toujours possible, mais peut-être que les deux valeurs peuvent être créées indépendamment l'une de l'autre?

Au lieu de:

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

Essayer:

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

Pour le rendre plus utile, ces deux méthodes peuvent partager une logique commune:

public ThingA createThingA(...) {
    doCommonThings(); // common logic
    // create thing A
}
public ThingB createThingB(...) {
    doCommonThings(); // common logic
    // create thing B
}

0

Passez une liste à votre méthode et remplissez-la, puis renvoyez la chaîne avec les noms, comme ceci:

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

Alors appelez-le comme ceci:

List<?> values = new ArrayList<?>();
String names = buildList(values);

-2

J'ai utilisé une approche très basique pour traiter les problèmes de retours multiples. Cela sert le but et évite la complexité.

Je l'appelle l' approche du séparateur de chaîne

Et il est efficace car il peut même renvoyer des valeurs de plusieurs types par exemple int, double, char, string, etc.

Dans cette approche, nous utilisons une chaîne qui est très peu susceptible de se produire en général. Nous l'appelons comme un séparateur. Ce séparateur serait utilisé pour séparer diverses valeurs lorsqu'il est utilisé dans une fonction

Par exemple, nous aurons notre retour final comme (par exemple) intValue separator doubleValue separator ... Et puis en utilisant cette chaîne, nous récupérerons toutes les informations nécessaires, qui peuvent également être de types différents

Le code suivant montrera le fonctionnement de ce concept

Le séparateur utilisé est ! @ # Et 3 valeurs sont renvoyées intVal, doubleVal et 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);
            }
        }

PRODUCTION

5
3.14
hello
BUILD SUCCESSFUL (total time: 2 seconds)

3
yuk. Énorme odeur de code. Analyse, au lieu d'utiliser les fonctionnalités orientées objet disponibles. IMO, l'un des pires exemples de codage que j'aie jamais vu. À moins que vous ne décriviez une situation où vous devez passer plusieurs valeurs entre deux programmes indépendants, ou toute autre communication inter-processus, et que vous n'avez pas accès à un mécanisme décent pour le faire (json ou autre).
ToolmakerSteve

-4

En C, vous le feriez en passant des pointeurs vers des espaces réservés pour les résultats sous forme d'arguments:

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

Essayons quelque chose de similaire, 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);

1
Cependant, dans un langage OO, il est généralement considéré comme préférable de faire ce que plusieurs personnes ont déjà suggéré quatre ans avant cette réponse: regrouper les deux valeurs liées en un seul objet (paire, tuple ou définition de classe personnalisée), puis avoir une liste de celles-ci objets. Cela évite d'avoir à faire circuler plusieurs listes. Cela devient particulièrement important si vous devez passer une telle paire (un élément de chacune de vos listes) à d'autres méthodes, pour un traitement ultérieur.
ToolmakerSteve

@ToolmakerSteve Pour clarifier: les listes sont destinées à avoir exactement un élément chacune et ne sont qu'un moyen d'implémenter un analogue au pointeur. Ils ne sont pas destinés à collecter plusieurs résultats, ni même à être utilisés au-delà de quelques lignes après l'appel de la méthode.
Adrian Panasiuk

-5

PASSER UN HASH À LA MÉTHODE ET LA POPULER ......

public void buildResponse (données de chaîne, réponse de carte);

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.