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 및 제네릭을 사용한 녹 슬림에 대한 참고 사항 :

  • 모두 a와 b불변입니다.
  • makePair정적 방법은 보일러 플레이트 타이핑에 도움이되며 Java 7의 다이아몬드 연산자는 덜 성가 시게합니다. 이것을 정말 멋지게 만드는 작업이 있습니다 : 제네릭이지만 지금은 괜찮을 것입니다. (cf PECS)
  • hashcode 과 equals 식에 의해 생성된다.
  • 컴파일 타임 캐스팅 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에서 방법 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];

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.