Come restituire più oggetti da un metodo Java?


173

Voglio restituire due oggetti da un metodo Java e mi chiedevo quale potrebbe essere un buon modo per farlo?

I possibili modi a cui riesco a pensare sono: return a HashMap(poiché i due Oggetti sono correlati) o return anArrayList di Objectoggetti.

Per essere più precisi, i due oggetti che voglio restituire sono (a) List di oggetti e (b) nomi separati da virgola dello stesso.

Voglio restituire questi due oggetti da un metodo perché non voglio scorrere l'elenco degli oggetti per ottenere i nomi separati da virgola (cosa che posso fare nello stesso ciclo in questo metodo).

In qualche modo, restituire a HashMapnon sembra un modo molto elegante per farlo.


1
L'Elenco e i CSV sono sostanzialmente diverse viste degli stessi dati? Sembra che ciò di cui hai bisogno sia un oggetto in cui hai un singolo Listriferimento e una sorta di tabella di ricerca.
James P.

Risposte:


128

Se si desidera restituire due oggetti, in genere si desidera restituire un singolo oggetto che incapsula invece i due oggetti.

È possibile restituire un elenco di NamedObjectoggetti come questo:

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

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

Quindi puoi facilmente restituire a List<NamedObject<WhateverTypeYouWant>>.

Inoltre: Perché dovresti voler restituire un elenco di nomi separato da virgole anziché un List<String>? O meglio ancora, restituisci a Map<String,TheObjectType>con le chiavi come nomi e valori degli oggetti (a meno che i tuoi oggetti non abbiano specificato l'ordine, nel qual caso a NavigableMappotrebbe essere quello che vuoi.


Il motivo per la restituzione dell'elenco separato da virgole è: Se non creo l'elenco qui, dovrei farlo nel chiamante eseguendo il ciclo tra gli oggetti (è necessario il valore CS). Forse, sto pre-ottimizzando inutilmente.
Jagmal,

2
Mi sono sempre chiesto perché Java non abbia una classe Pair <T, U> per questo motivo.
David Koelle,

Jagmal: sì, se l'unico rason per restituire l'elenco separato da virgole è questa ottimizzazione, allora dimenticalo.
Joachim Sauer,

Funziona bene solo se gli articoli che desideri restituire appartengono alla stessa classe o hanno almeno un antenato comune. Voglio dire, usare l'Oggetto al posto di Qualunque sia il tipo non è molto pulito.
David Hanak,

@David: sono d'accordo sul fatto che l'utilizzo di Object qui non sia molto accurato, ma poi restituire oggetti senza un antenato comune (tranne Object ovviamente) non è altrettanto accurato. Direi anche che è un odore di codice, se ne hai bisogno.
Joachim Sauer,

69

Se sai che restituirai due oggetti, puoi anche usare una coppia generica:

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

Modifica Un'implementazione più completa di quanto sopra:

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

    }

}

Note, principalmente intorno alla ruggine con Java e generici:

  • entrambi aeb sono immutabili.
  • makePairil metodo statico ti aiuta con la digitazione della piastra della caldaia, che l'operatore diamante in Java 7 renderà meno fastidioso. C'è un po 'di lavoro per rendere questo re davvero generico, ma ora dovrebbe essere ok. (vedi PECS)
  • hashcode e equals sono generati da eclipse.
  • il tempo di compilazione del casting in cast metodo è ok, ma non sembra del tutto giusto.
  • Non sono sicuro se i caratteri jolly siano presenti isInstance siano necessari.
  • Ho appena scritto questo in risposta ai commenti, solo a scopo illustrativo.

Di solito ho questa classe a bussare in ogni base di codice su cui lavoro. Aggiungerei anche: un'implementazione hashCode / equals, e possibilmente un metodo isInstance () e cast () statico.
James,

Certo, ci sono molti modi per rendere questa classe più intelligente e più comoda da usare. La versione sopra include quanto basta in una dichiarazione one-shot.
David Hanak,

@jamesh: ti dispiace scrivere la tua coppia in tutti i dettagli qui? Vorrei sapere come appare dopo aver fornito "un'implementazione hashCode / uguale a, e possibilmente un metodo isInstance () e cast () statico". Grazie.
Qiang Li,

@QiangLi - Generalmente generi l'hashcode e metodi uguali. Il metodo di istanza isInstance accetta due classi e si assicura che l'istanza a & b siano istanze di tali classi. Il cast prende una coppia <?,?> E la lancia con attenzione su una coppia <A, B>. Le implementazioni dovrebbero essere abbastanza facili (suggerimento: Class.cast (), Class.isInstance ())
jamesh

2
È Pairun'implementazione molto bella . Una piccola modifica che vorrei apportare: aggiungere un messaggio a ClassCastException. Altrimenti il ​​debug diventa un incubo se questo non riesce per qualche motivo. (e gli avvisi di soppressione rawtypes non sarebbero necessari se si eseguisse il cast Pair<?,?>(il che funziona, perché hai solo bisogno di Objectmetodi da ae b). Ti dispiace se modifico il codice?
Joachim Sauer,

25

Nel caso in cui il metodo che stai chiamando sia privato o chiamato da una posizione, prova

return new Object[]{value1, value2};

Il chiamante assomiglia a:

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

L'esempio Pair di David Hanak non ha alcun vantaggio sintattico ed è limitato a due valori.

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

E il chiamante assomiglia a:

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

7
La coppia ha un vantaggio in termini di controllo del tipo di classe
Hlex,

5
IMHO, non andare così: la dichiarazione dice troppo poco sui valori di ritorno attesi. AFAIK, è più ampiamente preferito creare classi generiche che specificano quanti parametri vengono restituiti e il tipo di tali parametri. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>, Ecc Poi un uso specifico mostra il numero ei tipi di parametri Pair<int, String> temp = ...o qualsiasi altra cosa.
ToolmakerSteve

22

È possibile utilizzare uno dei seguenti modi:

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) Utilizzo dell'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) Utilizzo di 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) Utilizzo di 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) Utilizzo della classe contenitore personalizzata

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) Utilizzo di 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) Utilizzo di Pair of 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

Quasi sempre finisco per definire le classi n-Tuple quando codice in Java. Per esempio:

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

So che è un po 'brutto, ma funziona e devi solo definire i tuoi tipi di tupla una volta. Le tuple sono qualcosa che manca davvero a Java.

EDIT: l'esempio di David Hanak è più elegante, in quanto evita di definire getter e mantiene immutabile l'oggetto.


9

Prima di Java 5, sarei d'accordo sul fatto che la soluzione Map non è l'ideale. Non ti darebbe il controllo del tipo di tempo di compilazione, quindi potrebbe causare problemi in fase di esecuzione. Tuttavia, con Java 5, abbiamo tipi generici.

Quindi il tuo metodo potrebbe apparire così:

public Map<String, MyType> doStuff();

MyType ovviamente è il tipo di oggetto che stai restituendo.

Fondamentalmente penso che restituire una mappa sia la soluzione giusta in questo caso perché è esattamente quello che vuoi restituire: una mappatura di una stringa su un oggetto.


Questo non funzionerà se uno dei nomi si scontra. Un elenco può contenere duplicati, ma una mappa non può (contenere chiavi duplicate).
tvanfosson,

Ovviamente. Stavo facendo ipotesi basate sulla domanda - forse ingiustamente :)
kipz,

Anche se la tua ipotesi è vera in questo caso, sto entrando nel dominio dell'ottimizzazione prematura (cosa che non dovrei fare).
Jagmal,

6

In alternativa, nelle situazioni in cui desidero restituire un numero di elementi da un metodo, a volte utilizzerò un meccanismo di callback anziché un contenitore. Funziona molto bene in situazioni in cui non posso specificare in anticipo quanti oggetti verranno generati.

Con il tuo problema particolare, sarebbe simile a questo:

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

mi dispiace per aver commentato una tua risposta molto vecchia, ma come vanno i callback per quanto riguarda la raccolta dei rifiuti? Sicuramente non ho una buona comprensione della gestione della memoria java, se hai un oggetto Acall object B.getResult()e B.getResult()chiama A.finishResult()come a callback, l'oggetto Bviene raccolto in modo inutile o rimane in giro fino a quando A non finisce ?? probabilmente una domanda stupida ma è una confusione fondamentale che ho!
wired00

6

Apache Commons ha tupla e tripla per questo:

  • ImmutablePair<L,R> Una coppia immutabile composta da due elementi Object.
  • ImmutableTriple<L,M,R> Una tripla immutabile composta da tre elementi Object.
  • MutablePair<L,R> Una coppia mutabile composta da due elementi Object.
  • MutableTriple<L,M,R> Una tripla mutabile composta da tre elementi Object.
  • Pair<L,R> Una coppia composta da due elementi.
  • Triple<L,M,R> Una tripla composta da tre elementi.

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


6

Mentre nel tuo caso, il commento può essere un buon modo per andare, in Android, puoi usare Pair . Semplicemente

return new Pair<>(yourList, yourCommaSeparatedValues);

5

Utilizzo del seguente oggetto Entry Esempio:

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

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

5

Per quanto riguarda il problema relativo a più valori di ritorno in generale, di solito utilizzo una piccola classe di supporto che avvolge un singolo valore di ritorno e viene passata come parametro al metodo:

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

(per tipi di dati primitivi uso variazioni minori per memorizzare direttamente il valore)

Un metodo che vuole restituire più valori verrebbe quindi dichiarato come segue:

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

Forse il principale svantaggio è che il chiamante deve preparare in anticipo gli oggetti di ritorno nel caso in cui voglia usarli (e il metodo dovrebbe verificare la presenza di puntatori null)

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

Vantaggi (rispetto ad altre soluzioni proposte):

  • Non è necessario creare una dichiarazione di classe speciale per singoli metodi e relativi tipi di restituzione
  • I parametri ottengono un nome e quindi sono più facili da differenziare quando si guarda la firma del metodo
  • Digitare safety per ciascun parametro

Grazie per una soluzione che fornisce nomi e sicurezza dei tipi a ciascun valore restituito, senza richiedere una dichiarazione di classe per set di tipi di valore restituiti.
ToolmakerSteve

3

Tutte le possibili soluzioni saranno un kludge (come oggetti container, la tua idea di HashMap, "valori di ritorno multipli" come realizzato tramite array). Consiglio di rigenerare l'elenco separato da virgole dall'elenco restituito. Il codice finirà per essere molto più pulito.


Sono d'accordo con te su questo, ma se lo faccio, finirò per ripetere due volte il ciclo (in realtà sto creando gli elementi dell'elenco uno a uno nel metodo esistente).
Jagmal,

1
@Jagmal: potresti ripetere il ciclo due volte, ma non importa la maggior parte delle volte (vedi risposta gizmos).
Joachim Sauer,

1
Sì, non provare a ottimizzare il codice a meno che non sia necessario. gizmo ha ragione.
Bombe,

3

Mantieni la semplicità e crea una classe per più risultati. Questo esempio accetta un ArrayList e un testo di messaggio da un databasehelper getInfo.

Dove si chiama la routine che restituisce più valori codificati:

multResult res = mydb.getInfo(); 

Nella routine getInfo si codifica:

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

e definire una classe 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;
}

}


2

A mio avviso, ci sono davvero tre scelte qui e la soluzione dipende dal contesto. Puoi scegliere di implementare la costruzione del nome nel metodo che produce l'elenco. Questa è la scelta che hai scelto, ma non credo sia la migliore. Stai creando un accoppiamento nel metodo produttore con il metodo consumo che non deve esistere. Altri chiamanti potrebbero non aver bisogno delle informazioni extra e tu calcoleresti informazioni extra per questi chiamanti.

In alternativa, il metodo chiamante potrebbe calcolare il nome. Se c'è un solo chiamante che ha bisogno di queste informazioni, puoi fermarti lì. Non hai dipendenze extra e mentre c'è un piccolo calcolo in più coinvolto, hai evitato di rendere il tuo metodo di costruzione troppo specifico. Questo è un buon compromesso.

Infine, è possibile che l'elenco stesso sia responsabile della creazione del nome. Questo è il percorso che seguirei se il calcolo deve essere eseguito da più di un chiamante. Penso che questo metta la responsabilità della creazione dei nomi con la classe che è più strettamente correlata agli oggetti stessi.

In quest'ultimo caso, la mia soluzione sarebbe quella di creare una classe Elenco specializzata che restituisca una stringa separata da virgole dei nomi degli oggetti che contiene. Rendi la classe abbastanza intelligente da costruire al volo la stringa del nome man mano che gli oggetti vengono aggiunti e rimossi da essa. Quindi restituire un'istanza di questo elenco e chiamare il metodo di generazione del nome secondo necessità. Anche se può essere quasi altrettanto efficace (e più semplice) ritardare semplicemente il calcolo dei nomi fino alla prima volta in cui viene chiamato il metodo e memorizzarlo (caricamento lento). Se aggiungi / rimuovi un oggetto, devi solo rimuovere il valore calcolato e farlo ricalcolare alla chiamata successiva.


2

Può fare qualcosa come una tupla in un linguaggio dinamico (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]);
}
}

e usare così

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


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

2

Ho seguito un approccio simile a quello descritto nelle altre risposte con alcune modifiche basate sul requisito che avevo, fondamentalmente ho creato le seguenti classi (per ogni evenienza, tutto è 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);
    }
}

Quindi, il mio requisito era semplice, nella classe di repository che raggiunge il DB, per ottenere i metodi che recuperano i dati dal DB, ho bisogno di controllare se fallito o avere successo, quindi, in caso di successo, avevo bisogno di giocare con l'elenco di ritorno , in caso di errore, interrompere l'esecuzione e notificare l'errore.

Quindi, ad esempio, i miei metodi sono così:

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
}

Dove ResultMessage è solo una classe con due campi (codice / messaggio) e Customer è qualsiasi classe con un gruppo di campi che proviene dal DB.

Quindi, per controllare il risultato, faccio solo questo:

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

In C ++ (STL) esiste una classe pair per raggruppare due oggetti. In Java Generics non è disponibile una classe pair, anche se c'è una certa richiesta . Puoi facilmente implementarlo da solo però.

Concordo tuttavia con alcune altre risposte che se è necessario restituire due o più oggetti da un metodo, sarebbe meglio incapsularli in una classe.


1

Perché non creare un WhateverFunctionResultoggetto che contenga i tuoi risultati e la logica necessaria per analizzare questi risultati, iterare poi allora ecc. Mi sembra che:

  1. Questi oggetti dei risultati sono intimamente legati insieme / correlati e appartengono insieme, oppure:
  2. non sono correlati, nel qual caso la tua funzione non è ben definita in termini di ciò che sta cercando di fare (cioè facendo due cose diverse)

Vedo questo tipo di problema spuntare ancora e ancora. Non aver paura di creare le tue classi contenitore / risultato che contengono i dati e le funzionalità associate per gestirlo. Se passi semplicemente le cose in giro in HashMapo simili, i tuoi clienti devono separare questa mappa e sgranocchiare i contenuti ogni volta che vogliono usare i risultati.


Perché è un PITA dover definire una classe ogni volta che è necessario restituire più valori, semplicemente perché il linguaggio manca di questa funzionalità comunemente utile;) Ma seriamente, molto spesso vale la pena fare ciò che suggerisci.
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

Questo non risponde esattamente alla domanda, ma poiché ciascuna delle soluzioni fornite presenta alcuni inconvenienti, suggerisco di provare a riformattare un po 'il codice, quindi è necessario restituire un solo valore.

Caso uno.

Hai bisogno di qualcosa dentro e fuori dal tuo metodo. Perché non calcolarlo all'esterno e passarlo al metodo?

Invece di:

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

Provare:

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

Questo dovrebbe coprire la maggior parte delle tue esigenze, poiché nella maggior parte dei casi un valore viene creato prima dell'altro e puoi dividerlo creando in due metodi. Lo svantaggio è che il metodo createThingsBha un parametro aggiuntivo rispetto a createThings, e forse stai passando esattamente lo stesso elenco di parametri due volte a metodi diversi.


Caso due.

La soluzione più ovvia di sempre e una versione semplificata del primo caso. Non è sempre possibile, ma forse entrambi i valori possono essere creati indipendentemente l'uno dall'altro?

Invece di:

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

Provare:

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

Per renderlo più utile, questi due metodi possono condividere una logica comune:

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

0

Passa un elenco al tuo metodo e popolalo, quindi restituisci la stringa con i nomi, in questo modo:

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

Quindi chiamalo così:

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

-2

Ho usato un approccio molto semplice per affrontare i problemi di rendimenti multipli. Serve allo scopo ed evita la complessità.

Lo chiamo l' approccio del separatore di stringhe

Ed è efficace in quanto può persino restituire valori di più tipi ad esempio int, double, char, string ecc

In questo approccio facciamo uso di una stringa che è molto improbabile che si verifichi in generale. Lo chiamiamo come separatore. Questo separatore verrebbe usato per separare vari valori quando usato in una funzione

Ad esempio avremo il nostro ritorno finale come (ad esempio) separatore intValue separatore doubleValue ... E poi usando questa stringa recupereremo tutte le informazioni richieste, che possono anche essere di diverso tipo

Il codice seguente mostrerà il funzionamento di questo concetto

Il separatore utilizzato è ! @ # E vengono restituiti 3 valori intVal, doubleVal e 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);
            }
        }

PRODUZIONE

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

3
che schiffo. Enorme odore di codice. Analisi, invece di utilizzare le funzionalità orientate agli oggetti disponibili. IMO, uno dei peggiori esempi di programmazione che abbia mai visto. A meno che non si descriva una situazione in cui è necessario passare più valori tra due programmi indipendenti, o altre comunicazioni tra processi, e in qualche modo non avere accesso a un meccanismo decente per farlo (json o altro).
ToolmakerSteve

-4

In C, lo faresti passando puntatori ai segnaposto per i risultati come argomenti:

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

Proviamo qualcosa di simile, in 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
Tuttavia, in un linguaggio OO, è generalmente preferibile fare ciò che molte persone hanno già suggerito quattro anni prima di questa risposta: raggruppare i due valori correlati in un oggetto (coppia, tupla o definizione di classe personalizzata) e quindi avere un elenco di quelli oggetti. In questo modo si evita la necessità di passare tra più elenchi. Ciò diventa particolarmente importante se è necessario passare una tale coppia (un elemento di ciascuna delle tue liste) ad altri metodi, per un'ulteriore elaborazione.
ToolmakerSteve

@ToolmakerSteve Per chiarire: le liste intendono avere esattamente un elemento ciascuna e sono solo un mezzo per implementare un analogo al pass-by-pointer. Non hanno lo scopo di raccogliere diversi risultati o addirittura essere utilizzati oltre un paio di righe dopo la chiamata del metodo.
Adrian Panasiuk,

-5

PASSARE UN TRATTAMENTO SUL METODO E POPOLARLO ......

public void buildResponse (dati stringa, risposta mappa);

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.