जावा विधि से कई वस्तुओं को वापस कैसे करें?


172

मैं एक जावा विधि से दो वस्तुओं को वापस करना चाहता हूं और सोच रहा था कि ऐसा करने का एक अच्छा तरीका क्या हो सकता है?

संभव तरीके मैं के बारे में सोच सकते हैं: बदले एक HashMap(के बाद से दो वस्तुओं से संबंधित हैं) या एक वापसी ArrayListकी Objectवस्तुओं।

अधिक सटीक होने के लिए, मैं जिन दो वस्तुओं को वापस करना चाहता हूं, वे हैं (ए) Listवस्तुओं की और (बी) अल्पविराम के अलग-अलग नाम।

मैं इन दोनों वस्तुओं को एक विधि से वापस करना चाहता हूं क्योंकि मैं अल्पविराम से अलग किए गए नामों को प्राप्त करने के लिए वस्तुओं की सूची के माध्यम से पुनरावृति नहीं करना चाहता (जो मैं इस विधि में एक ही लूप में कर सकता हूं)।

किसी तरह, लौटकर HashMapऐसा करने का एक बहुत ही सुंदर तरीका नहीं दिखता है।


1
क्या सूची और CSV मूल रूप से एक ही डेटा के अलग-अलग विचार हैं? ऐसा लगता है कि आपको क्या चाहिए एक ऐसी वस्तु है जहाँ आपके पास एक ही Listसंदर्भ और एक प्रकार का लुकअप टेबल है।
जेम्स पी।

संबंधित प्रश्न: stackoverflow.com/questions/53453058/…
John McClane

जवाबों:


128

यदि आप दो वस्तुओं को वापस करना चाहते हैं तो आप आमतौर पर एक ही वस्तु को वापस करना चाहते हैं जो दो वस्तुओं को इनकैप्सुलेट करता है।

आप NamedObjectइस तरह की वस्तुओं की सूची वापस कर सकते हैं :

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

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

तब आप आसानी से एक वापसी कर सकते हैं List<NamedObject<WhateverTypeYouWant>>

इसके अलावा: आप अल्पविराम से अलग किए गए नामों की सूची क्यों लौटाना चाहेंगे List<String>? या बेहतर अभी तक, Map<String,TheObjectType>कुंजी के नाम और वस्तुओं को मानों के साथ लौटाएं (जब तक कि आपकी वस्तुओं का निर्दिष्ट क्रम नहीं होता है, उस स्थिति में NavigableMapआप क्या चाहते हैं।


अल्पविराम से अलग की गई सूची वापस करने का कारण यह है: यदि मैं यहां सूची नहीं बनाता हूं, तो मुझे कॉलर में ऑब्जेक्ट्स के माध्यम से लूप करके ऐसा करना होगा (सीएस मान आवश्यक है)। शायद, मैं अनावश्यक रूप से पूर्व-अनुकूलन कर रहा हूं।
जगमाल

2
मुझे हमेशा आश्चर्य होता है कि जावा में इस कारण से Pair <T, U> वर्ग क्यों नहीं है।
डेविड कोएले

जगमाल: हाँ, अगर कॉमा से अलग की गई सूची को वापस करने का एकमात्र रासन यह अनुकूलन है, तो इसके बारे में भूल जाओ।
जोकिम सॉरे

यह केवल तभी अच्छी तरह से काम करता है जब आप जिन वस्तुओं को वापस करना चाहते हैं, वे एक ही वर्ग के हैं, या कम से कम एक सामान्य पूर्वज हैं। मेरा मतलब है, जो कुछ भी आप की जगह का उपयोग कर रहे हैंआप बहुत साफ नहीं है।
डेविड हनाक

@ डेविड: मैं मानता हूं कि यहां वस्तु का उपयोग करना बहुत साफ-सुथरा नहीं है, लेकिन फिर बिना किसी सामान्य पूर्वज के वस्तुओं को फिर से लौटाएं। मैं यह भी कहूंगा कि यह एक कोड गंध है, अगर आपको इसकी आवश्यकता है।
जोकिम सॉरे

69

यदि आप जानते हैं कि आप दो वस्तुओं को वापस करने जा रहे हैं, तो आप एक सामान्य जोड़ी का भी उपयोग कर सकते हैं:

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

उपरोक्त का अधिक पूर्ण रूप से गठित कार्यान्वयन संपादित करें :

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

    }

}

नोट्स, मुख्य रूप से जावा और जेनरिक के साथ जंग के आसपास:

  • दोनों aऔर bअपरिवर्तनीय है।
  • makePairस्थिर विधि आपको बॉयलर प्लेट टाइपिंग में मदद करती है, जो कि जावा 7 में डायमंड ऑपरेटर कम कष्टप्रद होगा। यह वास्तव में अच्छी री: जेनरिक बनाने के लिए कुछ काम है, लेकिन यह अब ठीक होना चाहिए। (cf पीईसीएस)
  • hashcodeऔर equalsग्रहण से उत्पन्न होते हैं।
  • castविधि में संकलित समय कास्टिंग ठीक है, लेकिन काफी सही नहीं लगता है।
  • मुझे यकीन नहीं है कि वाइल्डकार्ड isInstanceजरूरी हैं।
  • मैंने इसे केवल टिप्पणियों के जवाब में लिखा है, केवल उदाहरण के लिए।

मैं आमतौर पर इस वर्ग के बारे में दस्तक देता हूं जिसमें प्रत्येक कोडबेस मैं काम करता हूं। मैं यह भी जोड़ूंगा: एक हैशकोड / समान कार्यान्वयन, और संभवतः एक स्थिर isstance () और कास्ट () विधि।
रमेश

ज़रूर, इस वर्ग को स्मार्ट बनाने के लिए और उपयोग करने के लिए अधिक सुविधाजनक बनाने के कई तरीके हैं। ऊपर दिए गए संस्करण में एक-शॉट घोषणा में बस क्या पर्याप्त है।
डेविड हनाक

@jamesh: क्या आपको अपनी पूरी जानकारी यहाँ लिखने के लिए मन है? मैं यह जानना चाहूंगा कि "हैशकोड / समान कार्यान्वयन की आपूर्ति के बाद यह कैसा दिखता है, और संभवतः एक स्थिर isstance () और कास्ट () विधि है।" धन्यवाद।
किआंग ली

@QiangLi - मैं आमतौर पर हैशकोड और समान विधियों को उत्पन्न करता हूं। इंस्टेंस विधि है। इंस्टेंस दो वर्गों को लेता है और यह सुनिश्चित करता है कि इंस्टेंस के ए और बी उन कक्षाओं के उदाहरण हैं। कास्ट एक Pair <???> लेता है और ध्यान से इसे Pair <A, B> में डालता है। कार्यान्वयन काफी आसान होना चाहिए (संकेत: Class.cast (), Class.isInstance ())
jamesh

2
यह बहुत अच्छा Pairकार्यान्वयन है। एक छोटा बदलाव मैं करूँगा: के लिए एक संदेश जोड़ें ClassCastException। अन्यथा डिबगिंग एक बुरा सपना बन जाता है अगर यह किसी कारण से विफल हो जाता है। (और अगर आप काम करना चाहते हैं Pair<?,?>(जो काम करता है, क्योंकि आप केवल से की जरूरत Objectहै aऔर b) को डाली जाएगी, तो कच्चा-दबाना-चेतावनी अनावश्यक होगा । क्या आपको लगता है कि अगर मैं कोड को साझा करता हूं?
जोआचिम सॉर

25

जिस स्थिति में आप कॉल कर रहे हैं वह निजी है, या एक स्थान से कॉल किया गया है, तो प्रयास करें

return new Object[]{value1, value2};

फोन करने वाला ऐसा दिखता है:

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

डेविड हनक द्वारा जोड़ी के उदाहरण का कोई वाक्यगत लाभ नहीं है, और यह दो मूल्यों तक सीमित है।

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

और कॉल करने वाला ऐसा दिखता है:

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

7
जोड़ी का वर्ग प्रकार नियंत्रण लाभ है
Hlex

5
IMHO, इस तरह मत जाओ - घोषणा प्रत्याशित मूल्यों के बारे में बहुत कम कहती है। AFAIK, जेनेरिक कक्षाएं बनाने के लिए अधिक व्यापक रूप से पसंद किया जाता है जो निर्दिष्ट करते हैं कि कितने पैरामीटर वापस किए जा रहे हैं, और उन मापदंडों का प्रकार। Pair<T1, T2>, Tuple<T1, T2, T3>, Tuple<T1, T2, T3, T4>, आदि तो फिर एक विशिष्ट उपयोग के शो संख्या और मापदंडों के प्रकार Pair<int, String> temp = ...या जो कुछ भी।
टूलमेकरसैट

22

आप निम्नलिखित में से किसी भी तरीके का उपयोग कर सकते हैं:

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) सरणी का उपयोग करना

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 का उपयोग करना

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) हाशप का उपयोग करना

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) अपने कस्टम कंटेनर क्लास का उपयोग करना

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 का उपयोग करना

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) अपाचे कॉमन्स की जोड़ी का उपयोग करना

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

जावा में कोड होने पर मैं लगभग हमेशा n-Tuple वर्गों को परिभाषित करता हूं। उदाहरण के लिए:

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

मुझे पता है कि यह थोड़ा बदसूरत है, लेकिन यह काम करता है, और आपको बस एक बार अपने टपल प्रकार को परिभाषित करना होगा। Tuples कुछ जावा वास्तव में अभाव हैं।

EDIT: डेविड हैनाक का उदाहरण अधिक सुरुचिपूर्ण है, क्योंकि यह गेटिंग को परिभाषित करने से बचता है और फिर भी वस्तु को अपरिवर्तनीय रखता है।


9

जावा 5 से पहले, मैं इस बात से सहमत होना चाहूंगा कि मैप समाधान आदर्श नहीं है। यह आपको संकलित समय प्रकार की जाँच नहीं देगा ताकि रनटाइम पर समस्याएँ पैदा हो सकें। हालाँकि, जावा 5 के साथ, हमारे पास जेनेरिक प्रकार हैं।

तो आपकी विधि इस तरह दिख सकती है:

public Map<String, MyType> doStuff();

MyType निश्चित रूप से ऑब्जेक्ट का प्रकार है जो आप वापस कर रहे हैं।

मूल रूप से मुझे लगता है कि एक नक्शा वापस करना इस मामले में सही समाधान है क्योंकि यह वही है जो आप वापस लौटना चाहते हैं - किसी वस्तु के लिए स्ट्रिंग का मानचित्रण।


यदि कोई भी नाम टकराता है तो यह काम नहीं करेगा। एक सूची में डुप्लिकेट हो सकते हैं, लेकिन एक मैप (डुप्लिकेट कुंजी नहीं हो सकता)।
tvanfosson

बेशक। मैं इस सवाल के आधार पर धारणाएँ बना रहा था - शायद बहुत ही :)
kipz

यद्यपि आपकी धारणा इस मामले में सही है, मैं समय से पहले अनुकूलन के क्षेत्र में चल रहा हूं (जो मुझे नहीं करना चाहिए)।
जगमाल

6

वैकल्पिक रूप से, उन स्थितियों में जहां मैं एक विधि से कई चीजों को वापस करना चाहता हूं मैं कभी-कभी कंटेनर के बजाय कॉलबैक तंत्र का उपयोग करूंगा। यह उन परिस्थितियों में बहुत अच्छी तरह से काम करता है जहां मैं समय से पहले निर्दिष्ट नहीं कर सकता कि कितनी वस्तुओं को उत्पन्न किया जाएगा।

आपकी विशेष समस्या के साथ, यह कुछ इस तरह दिखाई देगा:

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

आपके बहुत पुराने उत्तर पर टिप्पणी करने के लिए खेद है, लेकिन कचरा संग्रहण के बारे में कॉलबैक कैसे जाते हैं? मुझे निश्चित रूप से स्मृति प्रबंधन की अच्छी समझ नहीं है java, अगर आपके पास ऑब्जेक्ट Aकॉल B.getResult()और ऑब्जेक्ट के रूप में B.getResult()कॉल A.finishResult()है callback, तो क्या वस्तु Bको कचरा इकट्ठा होता है या यह ए खत्म होने तक आसपास रहता है ?? शायद एक बेवकूफ सवाल है, लेकिन इसकी एक बुनियादी भ्रम मुझे है!
6

6

अपाचे कॉमन्स के पास इसके लिए तिगुना और तिगुना है:

  • ImmutablePair<L,R> एक अपरिवर्तनीय जोड़ी जिसमें दो ऑब्जेक्ट तत्व होते हैं।
  • ImmutableTriple<L,M,R> एक अपरिवर्तनीय ट्रिपल जिसमें तीन ऑब्जेक्ट तत्व होते हैं।
  • MutablePair<L,R> एक परिवर्तनशील जोड़ी जिसमें दो ऑब्जेक्ट तत्व होते हैं।
  • MutableTriple<L,M,R> एक उत्परिवर्तनीय त्रिगुण जिसमें तीन पिंड तत्व होते हैं।
  • Pair<L,R> एक जोड़ी जिसमें दो तत्व होते हैं।
  • Triple<L,M,R> तीन तत्वों से मिलकर एक ट्रिपल।

स्रोत: https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/package-summary.html


6

आपके मामले में, टिप्पणी Android में जाने के लिए एक अच्छा तरीका हो सकता है, आप उपयोग कर सकते हैं Pair । केवल

return new Pair<>(yourList, yourCommaSeparatedValues);

5

निम्नलिखित प्रविष्टि वस्तु का उपयोग उदाहरण:

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

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

5

सामान्य रूप से एकाधिक वापसी मानों के बारे में समस्या के बारे में मैं आमतौर पर एक छोटे सहायक वर्ग का उपयोग करता हूं जो एक एकल वापसी मान को लपेटता है और विधि के पैरामीटर के रूप में पारित किया जाता है:

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

(आदिम डेटाैटिप्स के लिए मैं मूल्य को सीधे स्टोर करने के लिए मामूली बदलाव का उपयोग करता हूं)

एक विधि जो कई मानों को वापस करना चाहती है उसे इस प्रकार घोषित किया जाएगा:

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

हो सकता है कि बड़ी कमी यह है कि फोन करने वाले को पहले से ही रिटर्न ऑब्जेक्ट्स तैयार करना होता है, जब वह उन्हें इस्तेमाल करना चाहता है (और विधि को अशक्त बिंदुओं की जांच करनी चाहिए)

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

लाभ (प्रस्तावित अन्य समाधानों की तुलना में):

  • आपको व्यक्तिगत विधियों और इसके वापसी प्रकारों के लिए एक विशेष वर्ग घोषणा बनाने की आवश्यकता नहीं है
  • मापदंडों को एक नाम मिलता है और इसलिए विधि हस्ताक्षर को देखते समय अंतर करना आसान होता है
  • प्रत्येक पैरामीटर के लिए सुरक्षा टाइप करें

एक ऐसे समाधान के लिए धन्यवाद, जो लौटाए गए प्रत्येक प्रकार के नाम और प्रकार की सुरक्षा देता है, लौटे मूल्य के प्रकारों के प्रति वर्ग घोषणा की आवश्यकता के बिना।
टूलमेकरसेव

3

सभी संभावित समाधान एक कीचड़ (जैसे कंटेनर ऑब्जेक्ट्स, आपका हैशपॉप विचार, "कई रिटर्न वैल्यू" जैसा कि सरणियों के माध्यम से महसूस किया जाएगा) होगा। मैं लौटी सूची से अल्पविराम से अलग की गई सूची को पुन: प्राप्त करने की सलाह देता हूं। कोड समाप्त हो जाएगा एक बहुत क्लीनर है।


मैं इस पर आपसे सहमत हूं लेकिन अगर मैं ऐसा करता हूं, तो मैं दो बार लूपिंग समाप्त कर दूंगा (मैं वास्तव में मौजूदा पद्धति में एक-एक करके सूची के तत्वों का निर्माण कर रहा हूं)।
जगमाल

1
@ जगमाल: आप दो बार लूप कर सकते हैं, लेकिन यह अधिकतर समय मायने नहीं रखता (देखें गिज़्मो जवाब)।
जोआचिम सॉरे

1
जब तक आपको वास्तव में नहीं करना है, हाँ, अपने कोड को अनुकूलित करने का प्रयास न करें। इसके बारे में दृष्टिकोण बहुत सही है।
बॉम्बे

3

इसे सरल रखें और कई परिणाम स्थिति के लिए एक वर्ग बनाएं। यह उदाहरण एक ArrayList और एक डेटाबेस से एक संदेश पाठ स्वीकार करता है getInfo।

जहाँ आप दिनचर्या को कॉल करते हैं जो आपके द्वारा दिए गए कई मान देता है:

multResult res = mydb.getInfo(); 

नियमित getInfo में आप कोड:

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

और के साथ एक वर्ग बहुभाषा को परिभाषित करें:

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

जैसा कि मैं देख रहा हूं कि यहां वास्तव में तीन विकल्प हैं और समाधान संदर्भ पर निर्भर करता है। आप सूची बनाने वाले विधि में नाम के निर्माण को लागू करने का विकल्प चुन सकते हैं। यह आपके द्वारा चुना गया विकल्प है, लेकिन मुझे नहीं लगता कि यह सबसे अच्छा है। आप निर्माता विधि में एक युग्मन बनाने के लिए उपभोग करने की विधि है जो मौजूद नहीं है। अन्य कॉलर्स को अतिरिक्त जानकारी की आवश्यकता नहीं हो सकती है और आप इन कॉलर्स के लिए अतिरिक्त जानकारी की गणना कर रहे होंगे।

वैकल्पिक रूप से, आप कॉलिंग विधि नाम की गणना कर सकते हैं। यदि केवल एक कॉलर है जिसे इस जानकारी की आवश्यकता है, तो आप वहां रुक सकते हैं। आपके पास कोई अतिरिक्त निर्भरता नहीं है और जबकि थोड़ी अतिरिक्त गणना शामिल है, आपने अपनी निर्माण पद्धति को भी विशिष्ट बनाने से परहेज किया है। यह एक अच्छा व्यापार है।

अंत में, आपके पास नाम बनाने के लिए सूची स्वयं जिम्मेदार हो सकती है। यह वह मार्ग है जिस पर मैं जाता अगर गणना एक से अधिक कॉलर द्वारा की जानी चाहिए। मुझे लगता है कि यह वर्ग के साथ नामों के निर्माण के लिए ज़िम्मेदारी डालता है जो स्वयं वस्तुओं से सबसे अधिक निकटता से संबंधित है।

बाद के मामले में, मेरा समाधान एक विशिष्ट सूची वर्ग बनाना होगा जो वस्तुओं के नामों के अल्पविराम से अलग स्ट्रिंग को लौटाता है। कक्षा को इतना स्मार्ट बनाएं कि वह मक्खी पर नाम स्ट्रिंग का निर्माण करे क्योंकि इसमें ऑब्जेक्ट जोड़े जाते हैं और इसे हटा दिया जाता है। फिर इस सूची का एक उदाहरण लौटाएं और आवश्यकतानुसार नाम पीढ़ी विधि को कॉल करें। हालांकि यह लगभग कुशल (और सरल) हो सकता है कि केवल नामों की गणना में देरी हो सकती है जब तक कि पहली बार विधि को नहीं बुलाया जाता है और इसे तब (आलसी लोडिंग) संग्रहीत किया जाता है। यदि आप किसी ऑब्जेक्ट को जोड़ते / हटाते हैं, तो आपको केवल परिकलित मान को निकालने की आवश्यकता है और इसे अगली कॉल पर पुनर्गणित किया जाना चाहिए।


2

गतिशील भाषा में ट्यूल जैसी कोई चीज कर सकते हैं (पायथन)

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

और इस तरह का उपयोग करें

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


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

2

मेरे द्वारा बताए गए आवश्यकता के आधार पर कुछ उत्तरों के साथ अन्य उत्तरों में वर्णित की तुलना में मैंने एक समान दृष्टिकोण का पालन किया, मूल रूप से मैंने निम्नलिखित कक्षाएं बनाईं (बस मामले में, सब कुछ जावा है):

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

फिर, मेरी आवश्यकता सरल थी, डीबी से डेटा प्राप्त करने की तुलना में गेट मेथड्स के लिए डीबी तक पहुंचने वाले रिपॉजिटरी क्लास में, मुझे यह जांचने की आवश्यकता है कि क्या यह विफल हुआ या सफल रहा, फिर, यदि सफल हुआ, तो मुझे रिटर्निंग सूची के साथ खेलने की आवश्यकता है , यदि विफल रहा, तो निष्पादन रोकें और त्रुटि को सूचित करें।

इसलिए, उदाहरण के लिए, मेरे तरीके इस प्रकार हैं:

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 सिर्फ दो फ़ील्ड (कोड / संदेश) के साथ एक वर्ग है और ग्राहक किसी भी वर्ग है, जो DB के क्षेत्र से आता है।

फिर, परिणाम की जांच करने के लिए मैं सिर्फ यही करता हूं:

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

सी ++ (एसटीएल) में दो वस्तुओं को बांधने के लिए एक जोड़ी वर्ग है। जावा जेनरिक में एक जोड़ी वर्ग उपलब्ध नहीं है, हालांकि कुछ मांग है है। आप इसे आसानी से लागू कर सकते हैं।

मैं हालांकि कुछ अन्य उत्तरों से सहमत हूं कि यदि आपको एक विधि से दो या अधिक वस्तुओं को वापस करने की आवश्यकता है, तो उन्हें कक्षा में एनकैप्सुलेट करना बेहतर होगा।


1

एक ऐसा WhateverFunctionResultऑब्जेक्ट क्यों न बनाएं जिसमें आपके परिणाम हों, और इन परिणामों को पार्स करने के लिए आवश्यक तर्क, फिर उस पर पुनरावृति आदि हो, ऐसा मुझे लगता है:

  1. ये परिणाम वस्तुओं को एक साथ / संबंधित रूप से बाँधते हैं और एक साथ होते हैं, या:
  2. वे असंबंधित हैं, जिस स्थिति में आपका कार्य अच्छी तरह से परिभाषित नहीं है कि वह क्या करने की कोशिश कर रहा है (यानी दो अलग-अलग काम कर रहा है)

मैं इस तरह की समस्या को बार-बार देखता हूं। अपने खुद के कंटेनर / परिणाम कक्षाएं बनाने के लिए डरो मत जो इसे संभालने के लिए डेटा और संबंधित कार्यक्षमता रखते हैं। यदि आप सामान को लगभग HashMapया इसी तरह से पास करते हैं, तो आपके ग्राहकों को इस मानचित्र को अलग करना होगा और हर बार सामग्री का उपयोग करने के लिए सामग्री को अलग करना होगा।


क्योंकि इसका PITA एक ​​वर्ग को परिभाषित करने के लिए होता है, जब भी आपको कई मानों को वापस करने की आवश्यकता होती है, केवल इसलिए कि भाषा में इस आमतौर पर उपयोगी सुविधा का अभाव है;) लेकिन गंभीरता से, जो आप सुझाव देते हैं वह अक्सर करने योग्य है।
टूलमेकरसेव

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

यह वास्तव में सवाल का जवाब नहीं दे रहा है, लेकिन चूंकि यहां दिए गए हर समाधान में कुछ कमियां हैं, इसलिए मैं सुझाव देता हूं कि अपने कोड को थोड़ा कम करने की कोशिश करें ताकि आपको केवल एक मूल्य वापस करने की आवश्यकता हो।

केस एक।

आपको अपने तरीके के साथ-साथ अंदर से भी कुछ चाहिए। क्यों नहीं इसे बाहर की गणना करें और इसे विधि को पारित करें?

के बजाय:

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

प्रयत्न:

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

यह आपकी अधिकांश आवश्यकताओं को कवर करना चाहिए, क्योंकि अधिकांश स्थितियों में एक मूल्य दूसरे से पहले बनाया जाता है और आप उन्हें दो तरीकों से बना सकते हैं। दोष यह है कि विधि createThingsBकी तुलना करने के लिए एक अतिरिक्त पैरामीटर है createThings, और संभवतः आप मापदंडों की एक ही सूची को दो बार अलग-अलग तरीकों से पास कर रहे हैं।


केस दो।

सबसे स्पष्ट समाधान कभी और केस एक का एक सरलीकृत संस्करण। यह हमेशा संभव नहीं है, लेकिन शायद दोनों मूल्य एक-दूसरे के स्वतंत्र रूप से बनाए जा सकते हैं?

के बजाय:

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

प्रयत्न:

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

इसे और अधिक उपयोगी बनाने के लिए, ये दो विधियाँ कुछ सामान्य तर्क साझा कर सकती हैं:

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

0

अपनी विधि के लिए एक सूची पास करें और इसे पॉप्युलेट करें, फिर स्ट्रिंग को नामों के साथ वापस लौटाएं, जैसे:

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

फिर इसे इस तरह से कॉल करें:

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

-2

मैं कई रिटर्न की समस्याओं से निपटने के लिए एक बहुत ही बुनियादी दृष्टिकोण का उपयोग कर रहा हूं। यह उद्देश्य को पूरा करता है, और जटिलता से बचा जाता है।

मैं इसे स्ट्रिंग विभाजक कहता हूं दृष्टिकोण

और यह प्रभावी है क्योंकि यह कई प्रकारों के मूल्यों को भी लौटा सकता है जैसे कि इंट, डबल, चार, स्ट्रिंग आदि के

इस दृष्टिकोण में हम एक स्ट्रिंग का उपयोग करते हैं जो आम तौर पर होने की संभावना नहीं है। हम इसे एक विभाजक के रूप में कहते हैं। किसी फ़ंक्शन में उपयोग किए जाने पर विभिन्न विभाजकों को अलग करने के लिए इस विभाजक का उपयोग किया जाएगा

उदाहरण के लिए, हम अपने अंतिम रिटर्न के रूप में (उदाहरण के लिए) intValue विभाजक doubleValue विभाजक ... और फिर इस स्ट्रिंग का उपयोग करके हम आवश्यक सभी जानकारी प्राप्त करेंगे, जो कि अलग-अलग प्रकार के भी हो सकते हैं

निम्नलिखित कोड इस अवधारणा के काम को दिखाएगा

उपयोग किया जाने वाला विभाजक है ! @ # और 3 मान intalal, doubleVal और 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);
            }
        }

आउटपुट

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

3
युक। विशाल कोड गंध। उपलब्ध ऑब्जेक्ट-ओरिएंटेड सुविधाओं का उपयोग करने के बजाय पार्सिंग। आईएमओ, मैंने कभी देखा कोडिंग के सबसे खराब उदाहरणों में से एक है। जब तक आप एक ऐसी स्थिति का वर्णन नहीं कर रहे हैं जहां आपको दो स्वतंत्र कार्यक्रमों, या अन्य अंतर-प्रक्रिया संचार के बीच कई मूल्यों को पारित करने की आवश्यकता होती है, और किसी भी तरह से ऐसा करने के लिए एक सभ्य तंत्र तक पहुंच की कमी होती है (json, या अन्य)।
टूलमेकरसेव

-4

सी में, आप इसे तर्क के रूप में परिणामों के लिए प्लेसहोल्डर्स को पॉइंटर्स पास करके करेंगे:

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

जावा में कुछ इसी तरह की कोशिश करते हैं।

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
हालाँकि, एक OO भाषा में, आमतौर पर यह करना बेहतर माना जाता है कि इस उत्तर से चार साल पहले ही कई लोगों ने क्या सुझाव दिए थे: दो संबंधित मानों को एक वस्तु (जोड़ी, तुच्छ या कस्टम वर्ग परिभाषा) में समूहित करें, और फिर उन लोगों की एक सूची बनाएं वस्तुओं। ऐसा करने से कई सूचियों के आसपास से गुजरने की आवश्यकता से बचा जाता है। यह विशेष रूप से महत्वपूर्ण हो जाता है यदि आगे की प्रक्रिया के लिए ऐसी जोड़ी (आपकी प्रत्येक सूची का एक तत्व) को अन्य तरीकों से पारित करने की आवश्यकता होती है।
टूलमेकरसेव

@ToolmakerSteve स्पष्ट करने के लिए: सूचियों का उद्देश्य प्रत्येक तत्व में एक समान है और पास-पास-पॉइंटर के एनालॉग को लागू करने के लिए केवल एक साधन है। वे कई परिणामों को इकट्ठा करने के लिए अभिप्रेत नहीं हैं, या यहां तक ​​कि विधि कॉल के बाद एक दो लाइनों से आगे उपयोग किया जा सकता है।
बजे एड्रियन पनासीक

-5

एक विधि में प्रवेश करें और इसे प्रस्तुत करें ......

सार्वजनिक शून्य buildResponse (स्ट्रिंग डेटा, मानचित्र प्रतिक्रिया);

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.