Java 메소드에서 여러 객체를 반환하는 방법은 무엇입니까?


172

Java 메소드에서 두 개의 객체를 반환하고 좋은 방법이 무엇인지 궁금합니다.

내가 생각할 수있는 가능한 방법은 a를 반환하거나 HashMap(두 개의 객체가 관련되어 있기 때문에) 객체를 반환하는 것 ArrayList입니다 Object.

더 정확하게 말하면 반환하려는 두 객체는 ​​(a) List객체와 (b) 동일한 이름의 쉼표로 구분 된 이름입니다.

객체 목록을 반복하여 쉼표로 구분 된 이름을 얻지 않기 때문에이 두 객체를 반환하고 싶습니다 (이 방법에서 동일한 루프에서 수행 할 수 있음).

어쨌든, a를 반환한다고 HashMap해서 매우 우아한 방법은 아닙니다.


1
목록과 CSV는 기본적으로 동일한 데이터의 다른 뷰입니까? 단일 List참조와 일종의 조회 테이블 이있는 객체가 필요한 것 같습니다.
제임스 P.

답변:


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>키가 객체의 이름과 값인 객체를 반환 하십시오 (객체가 순서를 지정하지 않은 경우 a NavigableMap가 원하는 것일 수 있습니다).


쉼표로 구분 된 목록을 반환하는 이유는 다음과 같습니다. 여기서 목록을 만들지 않으면 개체를 반복하여 호출자 에서이 작업을 수행해야합니다 (CS 값 필요). 아마도 불필요하게 사전 최적화 중입니다.
Jagmal

2
나는 왜 이런 이유로 Java에 Pair <T, U> 클래스가 없는지 항상 궁금했다.
David Koelle

Jagmal : 예, 쉼표로 구분 된 목록을 반환하는 유일한 레이 슨이이 최적화라면 잊어 버리십시오.
Joachim Sauer

반품하려는 항목이 같은 클래스이거나 최소한 공통 조상이있는 경우에만 작동합니다. WhateverTypeYouWant 대신 Object를 사용하는 것은 그리 깔끔하지 않습니다.
David Hanak

@David : 여기서 Object를 사용하는 것이 그리 깔끔하지는 않지만 공통 조상 (물론 Object 제외)이없는 객체를 다시 반환하는 것도 매우 깔끔하지 않다는 데 동의합니다. 필요한 경우 코드 냄새라고 말할 수도 있습니다.
Joachim Sauer

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

    }

}

Java 및 제네릭을 사용한 녹 슬림에 대한 참고 사항 :

  • 모두 ab불변입니다.
  • makePair정적 방법은 보일러 플레이트 타이핑에 도움이되며 Java 7의 다이아몬드 연산자는 덜 성가 시게합니다. 이것을 정말 멋지게 만드는 작업이 있습니다 : 제네릭이지만 지금은 괜찮을 것입니다. (cf PECS)
  • hashcodeequals 식에 의해 생성된다.
  • 컴파일 타임 캐스팅 cast메소드 는 괜찮지 만, 옳지 않은 것 같습니다.
  • 와일드 카드가 있는지 확실하지 않습니다. isInstance 가 필요한지 .
  • 나는 단지 설명 목적으로 주석에 대한 응답으로 이것을 작성했습니다.

나는 보통 내가 작업하는 각 코드베이스 에서이 클래스를 두드리고 있습니다. 또한 hashCode / equals 구현 및 정적 isInstance () 및 cast () 메소드를 추가합니다.
jamesh

물론이 클래스를보다 똑똑하고 사용하기 편리하게 만드는 방법은 여러 가지가 있습니다. 위의 버전에는 원샷 선언으로 충분한 내용이 포함되어 있습니다.
David Hanak

@ jamesh : 여기에 쌍을 자세하게 쓰시겠습니까? "hashCode / equals 구현 및 가능하면 정적 isInstance () 및 cast () 메서드"를 제공 한 후 어떻게 보이는지 알고 싶습니다. 감사합니다.
Qiang Li

@ QiangLi-나는 일반적으로 해시 코드 및 equals 메소드를 생성합니다. 인스턴스 메소드 isInstance는 두 개의 클래스를 사용하며 인스턴스의 a & b가 해당 클래스의 인스턴스인지 확인합니다. 캐스트는 Pair <?,?>를 가져와 조심스럽게 Pair <A, B>에 캐스트합니다. 구현은 매우 쉽게해야합니다 (힌트 : Class.cast (), Class.isInstance ())
jamesh

2
그것은 아주 좋은 Pair구현입니다. 한 가지 사소한 변경 :에 메시지를 추가하십시오 ClassCastException. 그렇지 않으면 어떤 이유로 든 이것이 실패하면 디버깅이 악몽이됩니다. 당신이 캐스팅하려는 경우 (그리고 rawtypes 억제-경고가 불필요하게 될 것이다 Pair<?,?>작동하는 (만 필요하기 때문에, Object에서 방법 ab) 수행 내가 코드를 조정할 될까요.?
요아힘 사우어

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

David Hanak의 Pair 예제는 구문상의 이점이 없으며 두 가지 값으로 제한됩니다.

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 = ...이든.
ToolmakerSteve

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) 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) 사용자 정의 컨테이너 클래스 사용

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

Java로 코딩 할 때 거의 항상 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;}
}

나는 그것이 추악하다는 것을 알고 있지만 효과가 있으며 튜플 유형을 한 번만 정의하면됩니다. 튜플은 Java에 실제로 부족한 것입니다.

편집 : David Hanak의 예는 게터 정의를 피하고 여전히 객체를 불변으로 유지하므로 더 우아합니다.


9

Java 5 이전에는 Map 솔루션이 이상적이지 않다는 것에 동의합니다. 컴파일 시간 유형 검사를 제공하지 않으므로 런타임에 문제가 발생할 수 있습니다. 그러나 Java 5에는 제네릭 형식이 있습니다.

따라서 방법은 다음과 같습니다.

public Map<String, MyType> doStuff();

물론 MyType은 반환하는 객체의 유형입니다.

기본적으로 나는 맵을 반환하는 것이 올바른 해결책이라고 생각합니다. 왜냐하면 그것이 반환하고자하는 것입니다-문자열을 객체에 매핑하는 것입니다.


이름이 충돌하면 작동하지 않습니다. 목록에는 중복 항목이 포함될 수 있지만지도에는 중복 키가 포함될 수 없습니다.
tvanfosson

물론이야. 나는 아마도이 질문에 근거하여 가정을하고 있었다 – 아마도
부당한

이 경우 귀하의 가정이 적용되지만 조기 최적화 영역으로 들어가고 있습니다 (이러하지 않아야 함).
Jagmal

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()A와를 callback객체 않는, BGET 쓰레기 수집하거나이 완료 될 때까지 주변에있어 않습니다? 아마도 어리석은 질문이지만 근본적인 혼란이 있습니다!
wired00

6

Apache Commons에는 다음과 같은 튜플과 트리플이 있습니다.

  • ImmutablePair<L,R> 두 개의 Object 요소로 구성된 불변 쌍입니다.
  • ImmutableTriple<L,M,R> 3 개의 Object 요소로 구성된 불변의 트리플.
  • MutablePair<L,R> 두 개의 Object 요소로 구성된 변경 가능한 쌍입니다.
  • MutableTriple<L,M,R> 3 개의 Object 요소로 구성된 가변 트리플.
  • 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

다음 Entry 객체 사용 예 :

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("...");
    //...
}

아마도 가장 큰 단점은 호출자가 반환 객체를 사용하려는 경우 미리 반환 객체를 준비해야한다는 것입니다 (그리고 메소드는 null 포인터를 확인해야합니다)

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

장점 (제안 된 다른 솔루션과 비교) :

  • 개별 메소드 및 리턴 유형에 대해 특수 클래스 선언을 작성할 필요가 없습니다.
  • 매개 변수는 이름을 얻으므로 메소드 서명을 볼 때 쉽게 구별 할 수 있습니다.
  • 각 매개 변수에 대한 유형 안전

반환 값 유형 집합마다 클래스 선언을 요구하지 않고 각 반환 값에 이름과 형식 안전을 제공하는 솔루션에 감사드립니다.
ToolmakerSteve

3

가능한 모든 솔루션은 컨테이너 객체, HashMap 아이디어, 배열을 통해 실현되는 "다중 반환 값"과 같은 문제입니다. 반환 된 목록에서 쉼표로 구분 된 목록을 다시 생성하는 것이 좋습니다. 코드는 훨씬 깨끗해집니다.


나는 이것에 당신에 동의하지만, 그렇게하면 두 번 반복됩니다 (실제로 기존 방법으로 목록 요소를 하나씩 만듭니다).
Jagmal

1
@ Jagmal : 두 번 반복 할 수 있지만 대부분 중요하지 않습니다 (기즈모 답변 참조).
Joachim Sauer

1
예, 실제로 필요한 경우가 아니면 코드를 최적화하려고하지 마십시오. 기즈모는 그것에 대해 매우 옳습니다.
Bombe

3

간단하게 유지하고 여러 결과 상황에 대한 클래스를 만듭니다. 이 예제는 데이터베이스 헬퍼 getInfo의 ArrayList 및 메시지 텍스트를 승인합니다.

여러 값을 반환하는 루틴을 호출하면 다음과 같이 코딩됩니다.

multResult res = mydb.getInfo(); 

getInfo 루틴에서 다음을 코딩합니다.

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

다음을 사용하여 multResult 클래스를 정의하십시오.

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

내가 알다시피 여기에는 실제로 세 가지 선택이 있으며 솔루션은 상황에 따라 다릅니다. 목록을 생성하는 메소드에서 이름 구성을 구현하도록 선택할 수 있습니다. 이것이 당신이 선택한 선택이지만, 그것이 최선이라고 생각하지 않습니다. 생산자 방법에서 필요하지 않은 소비 방법에 대한 커플 링을 작성 중입니다. 다른 발신자에게는 추가 정보가 필요하지 않을 수 있으며 이러한 발신자에 대한 추가 정보를 계산할 것입니다.

또는 호출 메소드가 이름을 계산하도록 할 수 있습니다. 이 정보가 필요한 발신자가 한 명 뿐인 경우 중지 할 수 있습니다. 추가 종속성이 없으며 추가 계산이 약간 필요하지만 구성 방법을 너무 구체적으로 만들지 않았습니다. 이것은 좋은 절충안입니다.

마지막으로, 목록 자체가 이름 작성을 담당하게 할 수 있습니다. 둘 이상의 발신자가 계산을 수행해야하는 경우이 경로를 선택합니다. 나는 이것이 객체 자체와 가장 밀접하게 관련된 클래스로 이름을 만드는 것에 대한 책임이 있다고 생각합니다.

후자의 경우 내 솔루션은 포함 된 객체 이름의 쉼표로 구분 된 문자열을 반환하는 특수한 List 클래스를 만드는 것입니다. 객체가 추가 및 제거 될 때 즉시 이름 문자열을 생성 할 수있을 정도로 클래스를 똑똑하게 만듭니다. 그런 다음이 목록의 인스턴스를 리턴하고 필요에 따라 이름 생성 메소드를 호출하십시오. 메소드 호출이 처음 호출 될 때까지 단순히 이름 계산을 지연시키고 저장 (지연 로딩)하는 것이 거의 효율적일 수 있습니다. 객체를 추가 / 제거하는 경우 계산 된 값만 제거하고 다음 호출시 다시 계산해야합니다.


2

동적 언어의 튜플과 같은 것을 할 수 있습니다 (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]);
}
}

이처럼 사용하십시오

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


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

2

필자는 요구 사항에 따라 약간의 조정으로 다른 답변에 설명 된 것과 비슷한 접근 방식을 따랐으며 기본적으로 다음 클래스를 만들었습니다 (모든 경우 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);
    }
}

그런 다음 DB에 도달하는 리포지토리 클래스에서 DB의 데이터를 검색하는 것보다 Get Methods에 대한 요구 사항이 간단했습니다. 실패했는지 또는 성공했는지 확인한 다음 성공하면 반환 목록으로 재생해야했습니다. 실패하면 실행을 중지하고 오류를 알립니다.

예를 들어 내 방법은 다음과 같습니다.

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는 두 개의 필드 (코드 / 메시지)가있는 클래스이고 Customer는 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

C ++ (STL)에는 두 객체를 묶기위한 페어 클래스가 있습니다. Java Generics에서는 페어 클래스를 사용할 수 없지만 몇 가지 요구 사항 이 있습니다. 그래도 쉽게 직접 구현할 수 있습니다.

그러나 메소드에서 둘 이상의 객체를 반환 해야하는 경우 클래스에서 캡슐화하는 것이 좋습니다.


1

왜 만들지 WhateverFunctionResult결과를 포함 객체, 그리고 으로 반복이 끝난 후 등이이 중 하나를 나에게 보인다 이러한 결과를 구문 분석하는 데 필요한 논리를 :

  1. 이러한 결과 개체는 밀접하게 함께 / 관련되어 있고 함께 속해 있거나 :
  2. 그것들은 서로 관련이 없으며,이 경우 함수는 수행하려는 작업 (즉, 두 가지 다른 일을 수행)의 관점에서 잘 정의되지 않습니다

이런 종류의 문제가 계속 반복되는 것을 봅니다. 이를 처리하기 위해 데이터 및 관련 기능을 포함하는 자체 컨테이너 / 결과 클래스를 작성하는 것을 두려워하지 마십시오. 단순히 HashMap유사 물이나 그와 비슷한 것을 전달하는 경우 고객은이 맵을 분리하여 결과를 사용할 때마다 컨텐츠를 가져와야합니다.


PITA는 여러 값을 반환해야 할 때마다 클래스를 정의해야하기 때문에이 언어에는 일반적으로 유용한 기능이 부족하기 때문입니다.) 그러나 진지하게, 제안하는 것은 종종 가치가 있습니다.
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

이것은 정확히 질문에 대한 대답은 아니지만 여기에 제공된 모든 솔루션에는 몇 가지 단점이 있으므로 코드를 약간 리팩터링하여 하나의 값만 반환하면 좋습니다.

사례 하나.

분석법 외부뿐만 아니라 내부에서도 무언가가 필요합니다. 왜 외부에서 계산하여 메소드에 전달하지 않습니까?

대신에:

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

시험:

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

대부분의 상황에서 하나의 값이 다른 값보다 먼저 생성되고 두 가지 방법으로 분할하여 생성 할 수 있기 때문에 이것은 대부분의 요구를 충족해야합니다. 단점은 메소드 에와 createThingsB비교할 수있는 추가 매개 변수가 있으며 createThings, 정확히 동일한 매개 변수 목록을 다른 메소드에 두 번 전달한다는 것입니다.


사례 2

가장 확실한 솔루션이며 단순화 된 버전의 경우가 있습니다. 항상 가능하지는 않지만 두 값을 서로 독립적으로 만들 수 있습니까?

대신에:

[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

여러 반환 문제를 해결하기 위해 매우 기본적인 접근 방식을 사용하고 있습니다. 목적을 달성하고 복잡성을 피합니다.

나는 그것을 문자열 분리기 접근법 이라고 부른다.

그리고 여러 유형의 값을 반환 할 수 있기 때문에 효과적입니다.int, double, char, string 등과 같은

이 방법에서는 일반적으로 발생하기 어려운 문자열을 사용합니다. 우리는 그것을 구분자로 부릅니다. 이 구분자는 함수에서 사용될 때 다양한 값을 분리하는 데 사용됩니다

예를 들어 intValue separator doubleValue separator ...와 같이 최종 반환 값을 얻게됩니다. 그리고이 문자열을 사용하여 필요한 모든 정보를 검색합니다.

다음 코드는이 개념의 작동을 보여줍니다.

사용 된 분리자는 ! @ # 이며 3 개의 값이 intVal, 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
수다. 거대한 코드 냄새. 사용 가능한 객체 지향 기능을 사용하는 대신 구문 분석 내가 본 것 중 최악의 코딩 사례 중 하나 인 IMO. 두 개의 독립적 인 프로그램 또는 다른 프로세스 간 통신간에 여러 값을 전달해야하는 상황을 설명하고 있지 않으면이를 수행하기위한 적절한 메커니즘 (json 또는 기타)에 액세스 할 수없는 상황을 설명하지 않는 한.
ToolmakerSteve

-4

C에서는 결과에 대한 자리 표시 자에 포인터를 인수로 전달하여이를 수행합니다.

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 언어에서는 일반적으로이 답변 4 년 전에 여러 사람들이 이미 제안한 작업을 수행하는 것이 바람직합니다. 두 개의 관련 값을 하나의 객체 (페어, 튜플 또는 사용자 정의 클래스 정의)로 그룹화 한 다음 해당 목록을 갖는 것이 좋습니다. 사물. 그렇게하면 여러 목록을 전달할 필요가 없습니다. 추가 처리를 위해 이러한 쌍 (각 목록의 한 요소)을 다른 방법으로 전달 해야하는 경우 특히 중요합니다.
ToolmakerSteve

@ToolmakerSteve 명확히하기 위해 : 목록은 각각 정확히 하나의 요소를 갖도록 의도되었으며 패스 바이 패스로 아날로그를 구현하는 수단 일뿐입니다. 그것들은 여러 결과를 수집하거나 메소드 호출 후 몇 줄 이상 사용되도록 의도되지 않았습니다.
Adrian Panasiuk

-5

방법에 해시를 전달하고 인기를 얻으십시오 ......

공공 무효 buildResponse (문자열 데이터,지도 응답);

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.