Bir Java yönteminden birden çok nesne nasıl döndürülür?


173

Bir Java yönteminden iki nesne döndürmek istiyorum ve bunu yapmak için iyi bir yol ne olabilir merak ediyordum?

Aklıma gelen olası yolu vardır: dönüşü HashMap(iki Nesneler ilişkilidir çünkü) veya bir dönüş ArrayListait Objectnesneler.

Daha açık olmak gerekirse, geri dönmek istediğim iki nesne (a) Listnesneler ve (b) virgülle ayrılmış adlardır.

Virgülle ayrılmış adları (ki bu yöntemde aynı döngüde yapabilirsiniz) almak için nesne listesi üzerinden yineleme yapmak istemiyorum çünkü bu iki nesne bir yöntemden dönmek istiyorum.

Her nasılsa, a'yı döndürmek HashMapçok zarif bir yol gibi görünmüyor.


1
Liste ve CSV'ler temel olarak aynı verilerin farklı görünümleri midir? İhtiyacınız olan şey, tek bir Listreferansınız ve bir çeşit arama tablonuzun olduğu bir Nesne gibi görünüyor .
James P.

Yanıtlar:


128

İki nesneyi döndürmek istiyorsanız, genellikle iki nesneyi içine alan tek bir nesneyi döndürmek istersiniz.

Bunun NamedObjectgibi nesnelerin bir listesini döndürebilirsiniz :

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

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

Sonra kolayca geri dönebilirsiniz a List<NamedObject<WhateverTypeYouWant>>.

Ayrıca: Neden a yerine virgülle ayrılmış bir ad listesi döndürmek istersiniz List<String>? Ya da daha iyisi, Map<String,TheObjectType>anahtarları nesnelerin adları ve değerleri olacak şekilde döndürün (nesneleriniz sipariş belirtmedikçe, bu durumda a NavigableMapistediğiniz gibi olabilir.


Virgülle ayrılmış listeyi döndürmenin nedeni: Listeyi burada oluşturmazsam, nesneleri nesneler arasında döngü yaparak bunu arayanda yapmam gerekir (CS değeri gereklidir). Belki de gereksiz yere ön optimizasyon yapıyorum.
Jagmal

2
Java'nın neden bu nedenle bir Pair <T, U> sınıfına sahip olmadığını merak ettim.
David Koelle

Jagmal: evet, virgülle ayrılmış listeyi döndürmek için tek rason bu optimizasyonsa, unutun.
Joachim Sauer

Bu, yalnızca iade etmek istediğiniz öğelerin aynı sınıfta olması veya en azından ortak bir ataya sahip olması durumunda işe yarar. Yani, WhateverTypeYouWant yerine Object kullanmak çok düzgün değil.
David Hanak

@David: Object'i burada kullanmanın çok düzgün olmadığını kabul ediyorum, ancak daha sonra ortak bir ata olmadan (elbette Object hariç) nesneleri de çok düzgün değilim. Hatta bir kod kokusu bile diyebilirim.
Joachim Sauer

69

İki nesneyi döndüreceğinizi biliyorsanız, genel bir çift de kullanabilirsiniz:

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

Düzenle Yukarıdakilerin daha eksiksiz bir şekilde uygulanması:

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

    }

}

Notlar, esas olarak Java ve jeneriklerle paslanma hakkında:

  • hem ave bdeğişken değildir.
  • makePairstatik yöntem, Java 7'deki elmas operatörünün daha az can sıkıcı hale getireceği kazan plakası tiplemesinde size yardımcı olur. Bunu gerçekten güzel yapmak için biraz iş var: jenerikler, ama şimdi tamam olmalı. (cf PECS)
  • hashcodeve equalstutulma ile üretilir.
  • castyöntem derleme zamanı döküm tamam, ama oldukça doğru görünmüyor.
  • Joker karakterlerin isInstancegerekli olup olmadığından emin değilim .
  • Bunu sadece açıklama amacıyla yazdım, sadece açıklama amaçlı.

Genellikle bu sınıf üzerinde çalıştığım her kod temasında çalıyor. Ayrıca ekleyeceğim: bir hashCode / eşittir uygulama ve muhtemelen statik bir isInstance () ve cast () yöntemi.
jamesh

Elbette, bu sınıfı daha akıllı ve daha kullanışlı hale getirmenin birçok yolu vardır. Yukarıdaki sürüm, tek seferlik bir bildiride yeterli olanı içerir.
David Hanak

@jamesh: Çiftinizi burada tüm ayrıntılarıyla yazmayı düşünür müsünüz? "Bir hashCode / eşittir uygulama ve muhtemelen statik bir isInstance () ve cast () yöntemi" sağladıktan sonra nasıl göründüğünü bilmek istiyorum. Teşekkür ederim.
Qiang Li

@QiangLi - Genellikle hashcode & eşittir yöntemleri oluştururum. İsInstance örneği yöntemi iki sınıf alır ve örneğin a & b örneğinin bu sınıfların örnekleri olmasını sağlar. Oyuncular bir Pair <?,?> Alır ve dikkatle bir Pair <A, B> 'ya verir. Uygulamalar oldukça kolay olmalıdır (ipucu: Class.cast (), Class.isInstance ())
jamesh

2
Bu çok güzel bir Pairuygulama. Bir küçük değişiklik yapamıyor ediyorum: bir mesaj ekleyin ClassCastException. Aksi takdirde, herhangi bir nedenle başarısız olursa hata ayıklama kabus haline gelir. size savururdum eğer (ve rawtypes bastırmak-uyarılar gereksiz olacağını Pair<?,?>hangisinin (yalnızca gerekir, çünkü Objectgelen yöntemler ave b) Do I kod çimdik sakıncası.?
Joachim Sauer

25

Aradığınız yöntemin özel olması veya bir konumdan çağrılması durumunda,

return new Object[]{value1, value2};

Arayan şöyle görünür:

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

David Hanak'ın Pair örneğinin sözdizimsel bir faydası yoktur ve iki değerle sınırlıdır.

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

Ve arayan şöyle görünür:

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

7

5
IMHO, bu tarafa gitme - deklarasyon beklenen getiri değerleri hakkında çok az şey söylüyor. AFAIK, kaç parametrenin döndürüleceğini ve bu parametrelerin türünü belirten genel sınıflar oluşturmak daha yaygın olarak tercih edilir. Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>Vb Ardından belirli kullanım gösterileri numarası ve parametrelerin tipleri Pair<int, String> temp = ...ya da her neyse.
ToolmakerSteve

22

Aşağıdaki yollardan birini kullanabilirsiniz:

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) Dizi Kullanımı

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) ArrayList'i Kullanma

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) HashMap Kullanımı

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) Özel kap sınıfınızı kullanma

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) AbstractMap.simpleEntry Kullanımı

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) Kullanarak Çifti ait 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

Java'da kod yazarken neredeyse her zaman n-Tuple sınıflarını tanımlayabilirim. Örneğin:

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

Biraz çirkin olduğunu biliyorum, ama işe yarıyor ve sadece tuple tiplerinizi tanımlamanız gerekiyor. Tuples, Java'nın gerçekten eksik olduğu bir şey.

DÜZENLEME: David Hanak'ın örneği, alıcıları tanımlamaktan kaçındığı ve nesneyi değişmez olduğu için daha zariftir.


9

Java 5'ten önce Harita çözümünün ideal olmadığını kabul ediyorum. Derleme zamanı türü denetimi vermez, bu nedenle çalışma zamanında sorunlara neden olabilir. Ancak, Java 5 ile Genel Türlerimiz var.

Yani yönteminiz şöyle görünebilir:

public Map<String, MyType> doStuff();

MyType, elbette geri döndürdüğünüz nesne türüdür.

Temelde bir Harita döndürmenin bu durumda doğru çözüm olduğunu düşünüyorum çünkü tam olarak geri dönmek istediğiniz şey budur - bir dizenin bir nesneye eşlenmesi.


Herhangi bir isim çarpışırsa bu işe yaramaz. Bir liste kopyalar içerebilir, ancak Harita (kopya anahtarlar içeremez) içeremez.
tvanfosson

Elbette. Soruya dayanarak varsayımlar yapıyordum - belki de gereksizce :)
kipz

Bu durumda varsayımınız doğru olsa da, erken optimizasyon alanına giriyorum (ki yapmamalıyım).
Jagmal

6

Alternatif olarak, bir yöntemden birkaç şey döndürmek istediğim durumlarda, bazen bir kap yerine bir geri arama mekanizması kullanacağım. Kaç tane nesne üretileceğini önceden belirleyemediğim durumlarda bu çok iyi çalışıyor.

Sizin özel probleminizle, şöyle bir şey olurdu:

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

çok eski bir cevabınız hakkında yorum yaptığınız için üzgünüm, ancak Çöp toplama ile ilgili geri aramalar nasıl gidiyor? Kesinlikle bellek yönetiminin anlamakta iyi yoksa javanesne varsa, Açağrı nesnesini B.getResult()ve B.getResult()çağrıları A.finishResult()bir şekilde callbacknesne yok, Bolsun çöp toplanan veya A bittikten kadar etrafında kalmak yok ?? muhtemelen aptalca bir soru ama onun temel bir karışıklık var!
kablolu

6

Apache Commons bunun için üçlü ve üçlüdür:

  • ImmutablePair<L,R> İki Nesne elemanından oluşan değişmez bir çift.
  • ImmutableTriple<L,M,R> Üç Nesne elemanından oluşan değişmez bir üçlü.
  • MutablePair<L,R> İki Nesne öğesinden oluşan değiştirilebilir bir çift.
  • MutableTriple<L,M,R> Üç Nesne öğesinden oluşan değiştirilebilir bir üçlü.
  • Pair<L,R> İki elementten oluşan bir çift.
  • Triple<L,M,R> Üç elementten oluşan üçlü.

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


6

Durumunuzdayken , yorum gitmek için iyi bir yol olabilir, Android'de kullanabilirsiniz Pair . basitçe

return new Pair<>(yourList, yourCommaSeparatedValues);

5

Aşağıdaki Giriş nesnesinin kullanımı Örnek:

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

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

5

Genel olarak birden fazla dönüş değeri ile ilgili sorunla ilgili olarak genellikle tek bir dönüş değerini saran ve yönteme parametre olarak iletilen küçük bir yardımcı sınıf kullanırım:

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

(ilkel veri türleri için değeri doğrudan saklamak için küçük varyasyonlar kullanırım)

Birden çok değer döndürmek isteyen bir yöntem daha sonra şu şekilde bildirilir:

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

Belki de en büyük dezavantajı, arayanın geri dönüş nesnelerini kullanmak istemesi durumunda önceden hazırlaması gerektiğidir (ve yöntem boş göstergeleri kontrol etmelidir)

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

Avantajlar (önerilen diğer çözümlere kıyasla):

  • Tek tek yöntemler ve dönüş türleri için özel bir sınıf bildirimi oluşturmanız gerekmez
  • Parametreler bir ad alır ve bu nedenle yöntem imzasına bakıldığında ayırt edilmesi daha kolaydır
  • Her parametre için tip güvenliği

Her döndürülen değere ad ve tür güvenliği veren, döndürülen değer türü kümesi başına sınıf bildirimi gerektirmeyen bir çözüm için teşekkür ederiz.
ToolmakerSteve

3

Tüm olası çözümler bir çamur olacaktır (kap nesneleri, HashMap fikriniz, diziler aracılığıyla gerçekleştirilen "çoklu dönüş değerleri" gibi). Döndürülen Listeden virgülle ayrılmış listenin yeniden oluşturulmasını öneririm. Kod çok daha temiz olacak.


Bu konuda size katılıyorum, ancak bunu yaparsam, iki kez döngü yapacağım (aslında mevcut yöntemde liste öğelerini tek tek oluşturuyorum).
Jagmal

1
@Jagmal: İki kez döngü yapabilirsiniz, ancak çoğu zaman önemli değildir (bkz. Gizmos cevabı).
Joachim Sauer

1
Evet, gerçekten gerekmedikçe kodunuzu optimize etmeye çalışmayın. gizmo bu konuda çok haklı.
Bombe

3

Basit tutun ve çoklu sonuç durumu için bir sınıf oluşturun. Bu örnek, bir veritabanı dizisi getInfo öğesinden bir ArrayList ve ileti metni kabul eder.

Kodladığınız birden çok değeri döndüren yordamı çağırdığınızda:

multResult res = mydb.getInfo(); 

Rutin getInfo'da şunları kodlayabilirsiniz:

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

ve aşağıdakilerle bir multultult sınıfı tanımlayın:

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

Gördüğüm gibi burada gerçekten üç seçenek var ve çözüm bağlama bağlı. Listeyi üreten yöntemde adın yapısını uygulamayı seçebilirsiniz. Seçtiğiniz seçim bu, ama bunun en iyisi olduğunu düşünmüyorum. Üretici yönteminde, var olması gerekmeyen tüketim yöntemine bir bağlantı oluşturuyorsunuz. Diğer arayanlar ekstra bilgiye ihtiyaç duymayabilir ve bu arayanlar için ekstra bilgi hesaplarsınız.

Alternatif olarak, çağıran yöntemin adı hesaplamasını sağlayabilirsiniz. Bu bilgiye ihtiyaç duyan yalnızca bir arayan varsa orada durabilirsiniz. Ekstra bağımlılığınız yok ve biraz fazladan hesaplama söz konusu olsa da, inşaat yönteminizi çok spesifik yapmaktan kaçındınız. Bu iyi bir değiş tokuş.

Son olarak, listenin kendisinin adı oluşturmaktan sorumlu olmasını sağlayabilirsiniz. Hesaplamanın birden fazla arayan tarafından yapılması gerekiyorsa, gideceğim yol budur. Bence bu, nesnelerin kendileriyle en yakından ilişkili olan sınıfla isimlerin yaratılmasına ilişkin sorumluluğu ortaya koyuyor.

İkinci durumda, çözümüm içerdiği nesnelerin adlarının virgülle ayrılmış bir dizesini döndüren özel bir List sınıfı oluşturmak olacaktır. Sınıfı, nesneler eklenirken ve ondan kaldırılırken ad dizesini anında oluşturması için yeterince akıllı olun. Ardından bu listenin bir örneğini döndürün ve ad oluşturma yöntemini gerektiği gibi çağırın. Her ne kadar yöntem ilk kez çağrılıncaya kadar adların hesaplanmasını geciktirmek ve daha sonra saklamak (tembel yükleme) neredeyse etkili (ve daha basit) olabilir. Bir nesne ekler / kaldırırsanız, yalnızca hesaplanan değeri kaldırmanız ve bir sonraki çağrıda yeniden hesaplanmasını sağlamanız gerekir.


2

Dinamik dilde bir demet gibi bir şey yapabilir (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]);
}
}

ve böyle kullan

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


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

2

Diğer cevaplarda açıklanandan benzer bir yaklaşımı izledim, ihtiyacım temelinde birkaç tweaks ile, temelde aşağıdaki sınıfları oluşturdum (Her ihtimale karşı, her şey 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);
    }
}

Daha sonra, benim gereksinim basitti, DB ulaşan Yöntemler için DB ulaşan depo Sınıfı, DB veri almak daha, başarısız veya başarılı olup olmadığını kontrol etmek gerekir, sonra başarılı, dönen listesiyle oynamak gerekiyordu , başarısız olursa, yürütmeyi durdurun ve hatayı bildirin.

Örneğin, yöntemlerim şöyle:

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
}

ResultMessage sadece iki alana sahip bir sınıf (kod / mesaj) ve Müşteri, DB'den gelen bir grup alana sahip herhangi bir sınıftır.

Sonra, sonucu kontrol etmek için sadece bunu yapmak:

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

C ++ (STL) 'de iki nesneyi gruplamak için bir çift sınıf vardır. Java Generics'te bir çift sınıf mevcut değildir, ancak buna bir miktar talep vardır . Yine de kolayca kendiniz uygulayabilirsiniz.

Bununla birlikte, bir yöntemden iki veya daha fazla nesne döndürmeniz gerekirse, bunları bir sınıfta kapsüllemenin daha iyi olacağını düşündüğüm diğer bazı cevapları kabul ediyorum.


1

Neden WhateverFunctionResultsonuçlarınızı içeren bir nesne oluşturmuyorsunuz ve bu sonuçları ayrıştırmak için gereken mantık, o zamana kadar tekrarlayın vb. Bana öyle geliyor ki:

  1. Bu sonuç nesneleri yakından birbirine bağlanır / ilişkilendirilir ve birbirine aittir veya:
  2. ilgisizdir, bu durumda işleviniz ne yapmaya çalıştığı konusunda iyi tanımlanmamıştır (yani iki farklı şey yapmak)

Bu tür bir sorunun tekrar tekrar ortaya çıktığını görüyorum. Bunu işlemek için verileri ve ilgili işlevselliği içeren kendi kapsayıcı / sonuç sınıflarınızı oluşturmaktan korkmayın. Sadece bir HashMapveya benzeri şeyleri iletirseniz, müşterileriniz bu haritayı birbirinden ayırmalı ve sonuçları her kullanmak istediklerinde içeriği gözden geçirmelidir.


Çünkü bu bir PITA, birden fazla değer döndürmeniz gerektiğinde bir sınıf tanımlamak zorunda, çünkü sadece bu yaygın olarak kullanışlı özellikten yoksun;) Ama cidden, önerdiğiniz şey genellikle yapmaya değer.
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

Bu tam olarak soruyu cevaplamıyor, ancak burada verilen her çözümün bazı dezavantajları olduğundan, kodunuzu biraz yeniden düzenlemeyi denemenizi öneririz, böylece sadece bir değer döndürmeniz gerekir.

Birinci durum.

Metodunuzun içinde ve dışında bir şeye ihtiyacınız var. Neden dışarıda hesaplayıp yönteme aktarmıyorsunuz?

Onun yerine:

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

Deneyin:

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

Çoğu durumda bir değer diğerinden önce yaratıldığı ve bunları iki yöntemle oluşturmayı bölebileceğiniz için, bu, gereksinimlerinizin çoğunu kapsamalıdır. Dezavantajı, yöntemin createThingsBkarşılaştırmalı olarak ekstra bir parametreye sahip olması createThingsve muhtemelen aynı parametre listesini iki kez farklı yöntemlere geçirmenizdir.


İkinci durum.

Şimdiye kadarki en açık çözüm ve birinci durumun basitleştirilmiş bir versiyonu. Her zaman mümkün değildir, ancak her iki değer de birbirinden bağımsız olarak oluşturulabilir?

Onun yerine:

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

Deneyin:

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

Daha kullanışlı hale getirmek için, bu iki yöntem bazı ortak mantığı paylaşabilir:

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

0

Yönteminize bir liste iletin ve doldurun, ardından Dizeyi aşağıdaki gibi adlarla döndürün:

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

Sonra şöyle deyin:

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

-2

Birden fazla geri dönüş problemleriyle başa çıkmak için çok temel bir yaklaşım kullanıyorum. Amaca hizmet eder ve karmaşıklığı önler.

Ben buna dize ayırıcı Yaklaşım diyorum

Ve int, double, char, string vb. Gibi Çoklu Türlerin değerlerini bile döndürebildiği için etkilidir

Bu yaklaşımda, genellikle gerçekleşmesi çok düşük olan bir dize kullanırız. Buna ayırıcı diyoruz. Bu ayırıcı, bir işlevde kullanıldığında çeşitli değerleri ayırmak için kullanılır

Örneğin, nihai dönüşümüzü (örneğin) intValue ayırıcı doubleValue ayırıcı olarak alacağız ... Ve sonra bu dizeyi kullanarak, farklı türlerde de olabilen gerekli tüm bilgileri alacağız.

Aşağıdaki kod bu kavramın çalışmasını gösterecektir

Kullanılan ayırıcı ! @ # Ve 3 değer intVal, doubleVal ve stringVal döndürülüyor

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

ÇIKTI

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

3
yuk. Büyük kod kokusu. Ayrıştırma, kullanılabilir Nesneye Dayalı özellikleri kullanmak yerine. IMO, şimdiye kadar gördüğüm en kötü kodlama örneklerinden biri. İki bağımsız program veya diğer süreçler arası iletişim arasında birden fazla değer iletmeniz gereken bir durumu tanımlamıyorsanız ve bir şekilde bunu yapmak için iyi bir mekanizmaya (json veya diğer) erişiminiz yoksa.
ToolmakerSteve

-4

C'de bunu sonuçlar için argüman olarak yer tutuculara ileterek yaparsınız:

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

Java'da benzer bir şey deneyelim.

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
Bununla birlikte, bir OO dilinde, genellikle bu cevaptan dört yıl önce birkaç kişinin önerdiği şeyleri yapmak tercih edilir: ilgili iki değeri bir nesneye (çift, grup veya özel sınıf tanımı) gruplayın ve ardından bunların bir listesine sahip olun itiraz ediyor. Bunu yapmak birden fazla listenin etrafından geçilmesi ihtiyacını ortadan kaldırır. Bu, daha fazla işlem için böyle bir çifti (listelerinizin her birinin bir öğesi) diğer yöntemlere geçirmeniz gerektiğinde özellikle önemlidir.
ToolmakerSteve

Açıklığa kavuşturmak için: listelerin her biri tam olarak bir öğeye sahip olacak şekilde tasarlanmıştır ve işaretçi için bir analog uygulamak için yalnızca bir araçtır. Birkaç sonuç toplamak veya hatta yöntem çağrısından sonra birkaç satırdan daha fazla kullanmak için tasarlanmamıştır.
Adrian Panasiuk

-5

YÖNTEMDE BİR GEÇİŞ YAPIN VE NÜFUSUNU ......

public void buildResponse (Dize verileri, Harita yanıtı);

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.