Bagaimana cara mengembalikan beberapa objek dari metode Java?


173

Saya ingin mengembalikan dua objek dari metode Java dan bertanya-tanya apa yang bisa menjadi cara yang baik untuk melakukannya?

Cara yang mungkin bisa saya pikirkan adalah: return HashMap(sejak dua Objects terkait) atau mengembalikan ArrayListdari Objectobjek.

Untuk lebih tepatnya, dua objek yang ingin saya kembalikan adalah (a) Listobjek dan (b) koma nama yang sama.

Saya ingin mengembalikan kedua Objek ini dari satu metode karena saya tidak ingin mengulangi daftar objek untuk mendapatkan nama yang dipisahkan koma (yang dapat saya lakukan dalam loop yang sama dalam metode ini).

Entah bagaimana, mengembalikan HashMaptidak terlihat cara yang sangat elegan untuk melakukannya.


1
Apakah Daftar dan CSV pada dasarnya berbeda pandangan dari data yang sama? Kedengarannya seperti yang Anda butuhkan adalah Obyek di mana Anda memiliki Listreferensi tunggal dan semacam tabel pencarian.
James P.

Jawaban:


128

Jika Anda ingin mengembalikan dua objek, Anda biasanya ingin mengembalikan satu objek yang merangkum kedua objek tersebut.

Anda dapat mengembalikan Daftar NamedObjectobjek seperti ini:

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

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

Maka Anda dapat dengan mudah mengembalikan a List<NamedObject<WhateverTypeYouWant>>.

Juga: Mengapa Anda ingin mengembalikan daftar nama yang dipisahkan koma, bukan a List<String>? Atau lebih baik lagi, kembalikan Map<String,TheObjectType>dengan kunci sebagai nama dan nilai objek (kecuali objek Anda telah menentukan urutan, dalam hal ini a NavigableMapmungkin yang Anda inginkan.


Alasan untuk mengembalikan daftar yang dipisahkan koma adalah: Jika saya tidak membuat daftar di sini, saya harus melakukan ini di pemanggil dengan perulangan melalui objek (nilai CS diperlukan). Mungkin, saya melakukan pra-optimasi secara tidak perlu.
Jagmal

2
Saya selalu bertanya-tanya mengapa Java tidak memiliki kelas Pair <T, U> karena alasan ini.
David Koelle

Jagmal: ya, jika satu-satunya alasan untuk mengembalikan daftar yang dipisahkan koma adalah pengoptimalan ini, maka lupakan saja.
Joachim Sauer

Ini hanya berfungsi dengan baik jika barang yang ingin Anda kembalikan memiliki kelas yang sama, atau setidaknya memiliki leluhur yang sama. Maksud saya, menggunakan Object sebagai pengganti Apapun JenisAnda Tidak sangat rapi.
David Hanak

@ David: Saya setuju bahwa menggunakan Object di sini tidak terlalu rapi, tapi sekali lagi mengembalikan objek tanpa leluhur yang sama (kecuali Obyek tentu saja) juga tidak terlalu rapi. Saya bahkan akan mengatakan itu bau kode, jika Anda membutuhkannya.
Joachim Sauer

69

Jika Anda tahu akan mengembalikan dua objek, Anda juga bisa menggunakan pasangan generik:

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

Sunting Implementasi yang lebih lengkap dari hal di atas:

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

    }

}

Catatan, terutama seputar karat dengan Java & generik:

  • keduanya adan btidak berubah.
  • makePairMetode statis membantu Anda dengan mengetik pelat ketel, yang membuat operator berlian di Java 7 tidak akan terlalu mengganggu. Ada beberapa pekerjaan untuk membuat ini benar-benar bagus: obat generik, tetapi harus ok-ish sekarang. (bdk. Pecs)
  • hashcodedan equalsdihasilkan oleh gerhana.
  • kompilasi casting waktu dalam castmetode ini ok, tetapi tampaknya tidak tepat.
  • Saya tidak yakin apakah wildcard isInstanceitu diperlukan.
  • Saya baru saja menulis ini sebagai tanggapan terhadap komentar, hanya untuk tujuan ilustrasi.

Saya biasanya memiliki kelas ini mengetuk di setiap basis kode yang saya kerjakan. Saya juga menambahkan: hashCode / sama dengan implementasi, dan mungkin metode isInstance () dan cast () statis.
jamesh

Tentu, ada banyak cara untuk membuat kelas ini lebih pintar dan nyaman digunakan. Versi di atas termasuk apa yang cukup dalam satu deklarasi tembakan.
David Hanak

@ jamesh: apakah Anda keberatan menulis Pasangan Anda dengan detail lengkap di sini? Saya ingin tahu bagaimana tampilannya setelah memasok "hashCode / sama dengan implementasi, dan mungkin metode isInstance () dan cast () statis." Terima kasih.
Qiang Li

@QiangLi - Saya biasanya menghasilkan kode hash & sama dengan. Metode instance adalah Instance mengambil dua kelas dan memastikan bahwa a & b instance adalah instance dari kelas-kelas tersebut. Cast mengambil Pair <?,?> Dan dengan hati-hati melemparkannya ke Pair <A, B>. Implementasinya harus cukup mudah (petunjuk: Class.cast (), Class.isInstance ())
jamesh

2
Itu Pairimplementasi yang sangat bagus . Satu perubahan kecil yang akan saya buat: tambahkan pesan ke ClassCastException. Kalau tidak, debugging menjadi mimpi buruk jika ini gagal karena suatu alasan. (dan rawtypes menekan-peringatan tidak akan diperlukan jika Anda akan dilemparkan ke Pair<?,?>(yang bekerja, karena Anda hanya perlu Objectmetode dari adan b). Apakah Anda keberatan jika saya mengubah kode?
Joachim Sauer

25

Jika metode yang Anda panggil bersifat pribadi, atau dipanggil dari satu lokasi, cobalah

return new Object[]{value1, value2};

Peneleponnya terlihat seperti:

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

Contoh Pair oleh David Hanak tidak memiliki manfaat sintaksis, dan terbatas pada dua nilai.

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

Dan peneleponnya tampak seperti:

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

7
Pasangan memiliki manfaat kontrol tipe kelas
Hlex

5
IMHO, jangan seperti ini - pernyataan itu mengatakan terlalu sedikit tentang nilai pengembalian yang diharapkan. AFAIK, lebih disukai untuk membuat kelas generik yang menentukan berapa banyak parameter yang dikembalikan, dan jenis parameter itu. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>, Dll Kemudian penggunaan tertentu menunjukkan jumlah dan jenis parameter Pair<int, String> temp = ...atau apa pun.
ToolmakerSteve

22

Anda dapat menggunakan salah satu dari cara berikut:

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) Menggunakan 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) Menggunakan 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) Menggunakan 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) Menggunakan kelas kontainer kustom Anda

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) Menggunakan 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) Menggunakan 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

Saya hampir selalu berakhir mendefinisikan kelas n-Tuple ketika saya kode di Java. Misalnya:

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

Saya tahu ini agak jelek, tetapi berhasil, dan Anda hanya perlu mendefinisikan jenis tuple sekali. Tuples adalah sesuatu yang sangat tidak dimiliki Java.

EDIT: Contoh David Hanak lebih elegan, karena menghindari mendefinisikan getter dan masih membuat objek tidak berubah.


9

Sebelum Java 5, saya agak setuju bahwa solusi Peta tidak ideal. Itu tidak akan memberi Anda kompilasi memeriksa jenis waktu sehingga dapat menyebabkan masalah saat runtime. Namun, dengan Java 5, kami memiliki Tipe Generik.

Jadi metode Anda bisa terlihat seperti ini:

public Map<String, MyType> doStuff();

MyType tentu saja menjadi tipe objek yang Anda kembalikan.

Pada dasarnya saya berpikir bahwa mengembalikan Peta adalah solusi yang tepat dalam kasus ini karena itulah yang ingin Anda kembalikan - pemetaan string ke objek.


Ini tidak akan berfungsi jika ada nama yang bertabrakan. Daftar dapat berisi duplikat, tetapi Peta tidak bisa (berisi kunci duplikat).
tvanfosson

Tentu saja. Saya membuat asumsi berdasarkan pada pertanyaan - mungkin unduely :)
kipz

Meskipun asumsi Anda berlaku dalam hal ini, saya masuk ke domain optimasi prematur (yang seharusnya tidak saya lakukan).
Jagmal

6

Atau, dalam situasi di mana saya ingin mengembalikan sejumlah hal dari suatu metode saya kadang-kadang akan menggunakan mekanisme panggilan balik alih-alih wadah. Ini bekerja sangat baik dalam situasi di mana saya tidak dapat menentukan sebelumnya berapa banyak objek yang akan dihasilkan.

Dengan masalah khusus Anda, akan terlihat seperti ini:

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

maaf karena mengomentari jawaban Anda yang sangat lama, tetapi bagaimana panggilan balik tentang pengumpulan sampah? Saya tentu saja tidak memiliki pemahaman yang baik tentang manajemen memori java, jika Anda memiliki objek Apanggilan objek B.getResult()dan B.getResult()panggilan A.finishResult()sebagai callback, apakah objek Bmendapatkan sampah yang dikumpulkan atau tinggal di sekitar sampai selesai? mungkin pertanyaan bodoh tapi itu adalah kebingungan mendasar yang saya miliki!
wired00

6

Apache Commons memiliki tuple dan triple untuk ini:

  • ImmutablePair<L,R> Sepasang abadi terdiri dari dua elemen Objek.
  • ImmutableTriple<L,M,R> Triple abadi yang terdiri dari tiga elemen Object.
  • MutablePair<L,R> Sepasang yang bisa berubah yang terdiri dari dua elemen Objek.
  • MutableTriple<L,M,R> Triple bisa berubah yang terdiri dari tiga elemen Objek.
  • Pair<L,R> Sepasang terdiri dari dua elemen.
  • Triple<L,M,R> Rangkap tiga terdiri dari tiga elemen.

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


6

Sementara dalam kasus Anda, komentar mungkin merupakan cara yang baik, di Android, Anda dapat menggunakannya Pair . Secara sederhana

return new Pair<>(yourList, yourCommaSeparatedValues);

5

Penggunaan Contoh Objek entri berikut:

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

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

5

Mengenai masalah tentang beberapa nilai pengembalian secara umum saya biasanya menggunakan kelas pembantu kecil yang membungkus nilai pengembalian tunggal dan dilewatkan sebagai parameter ke metode:

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

(untuk tipe data primitif saya menggunakan variasi kecil untuk langsung menyimpan nilai)

Metode yang ingin mengembalikan beberapa nilai akan dinyatakan sebagai berikut:

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

Mungkin kelemahan utama adalah bahwa pemanggil harus menyiapkan objek kembali terlebih dahulu jika dia ingin menggunakannya (dan metode harus memeriksa null pointer)

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

Keuntungan (dibandingkan dengan solusi lain yang diusulkan):

  • Anda tidak harus membuat deklarasi kelas khusus untuk metode individual dan jenis kembalinya
  • Parameter mendapatkan nama dan karena itu lebih mudah untuk dibedakan ketika melihat tanda tangan metode
  • Ketik keamanan untuk setiap parameter

Terima kasih atas solusi yang memberikan keamanan nama dan tipe untuk setiap nilai yang dikembalikan, tanpa memerlukan deklarasi kelas per set tipe nilai yang dikembalikan.
ToolmakerSteve

3

Semua solusi yang mungkin akan menjadi kludge (seperti objek kontainer, ide HashMap Anda, "beberapa nilai pengembalian" sebagaimana direalisasikan melalui array). Saya merekomendasikan regenerasi daftar yang dipisahkan koma dari Daftar yang dikembalikan. Kode akhirnya akan menjadi jauh lebih bersih.


Saya setuju dengan Anda dalam hal ini tetapi jika saya melakukannya, saya akan berakhir berulang dua kali (saya benar-benar membuat elemen daftar satu-per-satu dalam metode yang ada).
Jagmal

1
@ Jagmal: Anda mungkin mengulang dua kali, tetapi tidak masalah sebagian besar waktu (lihat jawaban gizmos).
Joachim Sauer

1
Ya, jangan mencoba mengoptimalkan kode Anda kecuali Anda benar-benar harus. alat sangat benar tentang itu.
Bom

3

Tetap sederhana dan buat kelas untuk situasi hasil berganda. Contoh ini menerima ArrayList dan teks pesan dari databasemembantu getInfo.

Di mana Anda memanggil rutin yang mengembalikan beberapa nilai yang Anda kode:

multResult res = mydb.getInfo(); 

Dalam kode rutin getInfo Anda:

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

dan tentukan kelas multResult dengan:

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

Seperti yang saya lihat sebenarnya ada tiga pilihan di sini dan solusinya tergantung pada konteksnya. Anda dapat memilih untuk mengimplementasikan konstruksi nama dalam metode yang menghasilkan daftar. Ini adalah pilihan yang telah Anda pilih, tetapi saya tidak berpikir itu adalah yang terbaik. Anda membuat penggandaan dalam metode produsen ke metode konsumsi yang tidak perlu ada. Penelepon lain mungkin tidak memerlukan informasi tambahan dan Anda akan menghitung informasi tambahan untuk penelepon ini.

Atau, Anda dapat meminta metode panggilan untuk menghitung nama. Jika hanya ada satu penelepon yang membutuhkan informasi ini, Anda bisa berhenti di situ. Anda tidak memiliki dependensi tambahan dan walaupun ada sedikit perhitungan tambahan yang terlibat, Anda menghindari membuat metode konstruksi Anda terlalu spesifik. Ini adalah trade-off yang bagus.

Terakhir, Anda dapat membuat daftar itu sendiri yang bertanggung jawab untuk membuat nama. Ini adalah rute yang akan saya tuju jika perhitungan perlu dilakukan oleh lebih dari satu penelepon. Saya pikir ini menempatkan tanggung jawab untuk penciptaan nama-nama dengan kelas yang paling terkait dengan objek itu sendiri.

Dalam kasus terakhir, solusi saya adalah membuat kelas Daftar khusus yang mengembalikan string yang dipisahkan oleh koma dari nama objek yang dikandungnya. Buat kelas cukup pintar sehingga ia membangun string nama dengan cepat saat objek ditambahkan dan dihapus darinya. Kemudian kembalikan instance dari daftar ini dan panggil metode pembuatan nama sesuai kebutuhan. Meskipun mungkin hampir sama efisien (dan lebih sederhana) untuk hanya menunda perhitungan nama sampai pertama kali metode dipanggil dan menyimpannya kemudian (lazy loading). Jika Anda menambah / menghapus objek, Anda hanya perlu menghapus nilai yang dihitung dan membuatnya dihitung ulang pada panggilan berikutnya.


2

Dapat melakukan beberapa hal seperti tuple dalam bahasa dinamis (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]);
}
}

dan gunakan seperti ini

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


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

2

Saya mengikuti pendekatan yang sama dari yang dijelaskan dalam jawaban lain dengan beberapa penyesuaian berdasarkan persyaratan yang saya miliki, pada dasarnya saya membuat kelas berikut (Untuk berjaga-jaga, semuanya adalah Jawa):

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

Kemudian, persyaratan saya sederhana, di kelas repositori yang mencapai DB, untuk Metode Mendapatkan daripada mengambil data dari DB, saya perlu memeriksa apakah gagal atau berhasil, maka, jika berhasil, saya perlu bermain dengan daftar kembali , jika gagal, hentikan eksekusi dan beri tahu kesalahan.

Jadi, misalnya, metode saya seperti ini:

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
}

Di mana ResultMessage hanya kelas dengan dua bidang (kode / pesan) dan Pelanggan adalah kelas apa pun dengan sekelompok bidang yang berasal dari DB.

Kemudian, untuk memeriksa hasilnya saya hanya melakukan ini:

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

Di C ++ (STL) ada kelas pasangan untuk menggabungkan dua objek. Dalam Java Generics, kelas pasangan tidak tersedia, meskipun ada beberapa permintaan untuk itu. Anda dapat dengan mudah menerapkannya sendiri.

Namun saya setuju dengan beberapa jawaban lain bahwa jika Anda perlu mengembalikan dua atau lebih objek dari suatu metode, akan lebih baik untuk merangkum mereka dalam sebuah kelas.


1

Mengapa tidak membuat WhateverFunctionResultobjek yang berisi hasil Anda, dan logika yang diperlukan untuk mem-parsing hasil ini, beralih lebih dari itu dll. Sepertinya bagi saya bahwa:

  1. Objek-objek hasil ini saling terkait erat / terkait dan dimiliki bersama, atau:
  2. mereka tidak terkait, dalam hal ini fungsi Anda tidak didefinisikan dengan baik dalam hal apa yang coba dilakukan (yaitu melakukan dua hal yang berbeda)

Saya melihat masalah semacam ini muncul lagi dan lagi. Jangan takut untuk membuat kelas wadah / hasil Anda sendiri yang berisi data dan fungsionalitas terkait untuk menangani hal ini. Jika Anda hanya membagikan barang-barang di dalam HashMapatau serupa, maka klien Anda harus menarik peta ini dan mengosongkan isinya setiap kali mereka ingin menggunakan hasilnya.


Karena itu adalah PITA harus mendefinisikan kelas kapan pun Anda perlu mengembalikan beberapa nilai, hanya karena bahasa tidak memiliki fitur yang umumnya bermanfaat ini;) Tetapi serius, apa yang Anda sarankan sangat sering dilakukan.
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

Ini sebenarnya bukan menjawab pertanyaan, tetapi karena setiap solusi yang diberikan di sini memiliki beberapa kelemahan, saya sarankan untuk mencoba memperbaiki kode Anda sedikit sehingga Anda hanya perlu mengembalikan satu nilai.

Kasus satu.

Anda membutuhkan sesuatu di dalam maupun di luar metode Anda. Mengapa tidak menghitungnya di luar dan meneruskannya ke metode?

Dari pada:

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

Mencoba:

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

Ini harus mencakup sebagian besar kebutuhan Anda, karena dalam sebagian besar situasi satu nilai dibuat sebelum yang lain dan Anda dapat memisahnya dengan dua metode. Kekurangannya adalah bahwa metode createThingsBmemiliki parameter tambahan yang dibandingkan createThings, dan mungkin Anda melewatkan daftar parameter yang sama persis dua kali ke metode yang berbeda.


Kasus dua.

Solusi paling jelas yang pernah ada dan versi sederhana dari case satu. Itu tidak selalu mungkin, tetapi mungkin kedua nilai dapat dibuat secara independen satu sama lain?

Dari pada:

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

Mencoba:

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

Agar lebih bermanfaat, kedua metode ini dapat berbagi beberapa logika umum:

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

0

Kirim daftar ke metode Anda dan isi, lalu kembalikan String dengan nama-nama, seperti ini:

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

Kemudian panggil seperti ini:

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

-2

Saya telah menggunakan pendekatan yang sangat mendasar untuk menangani masalah pengembalian berganda. Ini melayani tujuan, dan menghindari kompleksitas.

Saya menyebutnya pemisah string Pendekatan

Dan itu efektif karena bahkan dapat mengembalikan nilai dari Berbagai Jenis mis. Int, dobel, karakter, string dll

Dalam pendekatan ini kami menggunakan string yang sangat tidak mungkin terjadi secara umum. Kami menyebutnya sebagai pemisah. Pemisah ini akan digunakan untuk memisahkan berbagai nilai saat digunakan dalam suatu fungsi

Sebagai contoh, kita akan memiliki pengembalian akhir sebagai (misalnya) intValue separator doubleValue separator ... Dan kemudian menggunakan string ini kita akan mengambil semua informasi yang diperlukan, yang bisa dari jenis yang berbeda juga

Kode berikut akan menunjukkan cara kerja konsep ini

Pemisah yang digunakan adalah ! @ # Dan 3 nilai sedang dikembalikan ke intVal, doubleVal, dan 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);
            }
        }

KELUARAN

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

3
yuk. Bau kode besar. Parsing, alih-alih menggunakan fitur Berorientasi Objek yang tersedia. IMO, salah satu contoh pengkodean terburuk yang pernah saya lihat. Kecuali Anda menggambarkan situasi di mana Anda perlu memberikan beberapa nilai antara dua program independen, atau komunikasi antar-proses lainnya, dan entah bagaimana tidak memiliki akses ke mekanisme yang layak untuk melakukannya (json, atau lainnya).
ToolmakerSteve

-4

Di C, Anda akan melakukannya dengan memberikan pointer ke placeholder untuk hasilnya sebagai argumen:

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

Mari kita coba yang serupa, di Jawa.

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
Namun dalam bahasa OO, umumnya dianggap lebih baik untuk melakukan apa yang sudah disarankan beberapa orang empat tahun sebelum jawaban ini: kelompokkan dua nilai terkait menjadi satu objek (pasangan, tuple, atau definisi kelas khusus), dan kemudian memiliki daftar itu benda. Melakukan hal itu menghindari keharusan untuk membagikan banyak daftar. Ini menjadi sangat penting jika perlu meneruskan pasangan semacam itu (satu elemen dari masing-masing daftar Anda) ke metode lain, untuk diproses lebih lanjut.
ToolmakerSteve

@ToolmakerSteve Untuk memperjelas: daftar dimaksudkan untuk masing-masing memiliki tepat satu elemen dan hanya sarana untuk mengimplementasikan analog ke pass-by-pointer. Mereka tidak dimaksudkan untuk mengumpulkan beberapa hasil, atau bahkan digunakan lebih jauh dari beberapa baris setelah pemanggilan metode.
Adrian Panasiuk

-5

LULUS HASH KE METODE DAN POPULASI IT ......

public void buildResponse (Data string, Respons peta);

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.