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

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

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

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

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

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



답변

두 객체를 반환하려면 일반적으로 두 객체를 캡슐화하는 단일 객체를 반환하려고합니다.

다음 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가 원하는 것일 수 있습니다).


답변

두 개의 객체를 반환한다는 것을 알고 있다면 일반 쌍을 사용할 수도 있습니다.

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 가 필요한지 .
  • 나는 단지 설명 목적으로 주석에 대한 응답으로 이것을 작성했습니다.

답변

호출하는 메소드가 비공개이거나 한 위치에서 호출 된 경우 시도하십시오

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;


답변

다음 방법 중 하나를 사용할 수 있습니다.

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


답변

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의 예는 게터 정의를 피하고 여전히 객체를 불변으로 유지하므로 더 우아합니다.


답변

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

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

public Map<String, MyType> doStuff();

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

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


답변

또는 메서드에서 여러 가지를 반환하려는 경우 컨테이너 대신 콜백 메커니즘을 사용하는 경우가 있습니다. 이것은 얼마나 많은 객체가 생성 될지 미리 지정할 수없는 상황에서 매우 잘 작동합니다.

특정 문제로 다음과 같이 보일 것입니다.

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