[java] Java SE 8에 페어 또는 튜플이 있습니까?

Java SE 8에서 게으른 기능 연산으로 놀고 있으며 두 번째 요소 를 기반으로 한 쌍 / 튜플에 map색인 i을 만들고 마지막으로 색인 만 출력 하려고합니다 .(i, value[i])filtervalue[i]

여전히이 문제를 겪어야 합니까? Java에서 C ++ Pair <L, R>에 해당하는 것은 무엇입니까? 람다와 개울의 대담한 새로운 시대에?

업데이트 : 나는 아래 답변 중 하나에서 @dkatzel이 제공하는 깔끔한 솔루션을 가진 다소 단순화 된 예를 제시했습니다. 그러나 일반화 되지는 않습니다 . 따라서보다 일반적인 예를 추가하겠습니다.

package com.example.test;

import java.util.ArrayList;
import java.util.stream.IntStream;

public class Main {

  public static void main(String[] args) {
    boolean [][] directed_acyclic_graph = new boolean[][]{
        {false,  true, false,  true, false,  true},
        {false, false, false,  true, false,  true},
        {false, false, false,  true, false,  true},
        {false, false, false, false, false,  true},
        {false, false, false, false, false,  true},
        {false, false, false, false, false, false}
    };

    System.out.println(
        IntStream.range(0, directed_acyclic_graph.length)
        .parallel()
        .mapToLong(i -> IntStream.range(0, directed_acyclic_graph[i].length)
            .filter(j -> directed_acyclic_graph[j][i])
            .count()
        )
        .filter(n -> n == 0)
        .collect(() -> new ArrayList<Long>(), (c, e) -> c.add(e), (c1, c2) -> c1.addAll(c2))
    );
  }

}

이것은 모두 세 개의 열에 대한 카운트 에 해당하는 잘못된 출력을 제공 합니다 . 내가 필요한 것은 이 세 열의 지표 입니다. 올바른 출력은이어야합니다 . 이 결과를 어떻게 얻을 수 있습니까?[0, 0, 0]false[0, 2, 4]



답변

업데이트 : 이 답변은 원래 질문에 대한 답변입니다 . Java SE 8에 페어 또는 튜플이 있습니까? (그리고 암시 적으로, 그렇지 않다면 왜 안됩니까?) OP는 더 완전한 예제로 질문을 업데이트했지만 어떤 종류의 쌍 구조를 사용하지 않고도 해결할 수있는 것처럼 보입니다. [OP의 메모 : 여기 에 다른 정답이 있습니다.]


짧은 대답은 ‘아니요’입니다. 자신의 롤을 구현하거나이를 구현하는 여러 라이브러리 중 하나를 가져와야합니다.

PairJava SE에서 클래스를 갖는 것이 제안되고 적어도 한 번 거부되었습니다. OpenJDK 메일 링리스트 중 하나 에서이 토론 스레드 를 참조하십시오 . 트레이드 오프는 분명하지 않습니다. 한편으로 다른 라이브러리와 응용 프로그램 코드에는 많은 Pair 구현이 있습니다. 이는 필요를 보여 주며, 이러한 클래스를 Java SE에 추가하면 재사용 및 공유가 증가합니다. 반면에 Pair 클래스를 사용하면 필요한 유형과 추상화를 만들지 않고 Pairs 및 Collections에서 복잡한 데이터 구조를 만드는 유혹을 더할 수 있습니다. (그것이 스레드에서 보낸 Kevin Bourillion의 메시지에 대한 역설입니다 .)

나는 모든 사람이 그 전체 이메일 스레드를 읽는 것이 좋습니다. 놀랍도록 통찰력이 있으며 흠이 없습니다. 꽤 설득력이 있습니다. 처음 시작했을 때, “예, Java SE에는 Pair 클래스가 있어야합니다”라고 생각했지만 스레드가 끝날 무렵에는 마음이 바뀌 었습니다.

그러나 JavaFX에는 javafx.util.Pair 클래스가 있습니다. JavaFX의 API는 Java SE API와 별도로 발전했습니다.

링크 된 질문에서 알 수 있듯이 Java의 C ++ 쌍에 해당하는 것은 무엇입니까? 이러한 단순한 API를 둘러싼 상당히 큰 디자인 공간이 있습니다. 객체가 불변이어야합니까? 그것들은 직렬화 가능해야합니까? 비교할 수 있어야합니까? 수업은 마지막이어야합니까? 두 요소를 주문해야합니까? 인터페이스 또는 클래스 여야합니까? 왜 쌍에서 멈춰? 트리플, 쿼드 또는 N 튜플이 아닌 이유는 무엇입니까?

물론 요소의 피할 수없는 이름 지정이 있습니다.

  • (a, b)
  • (첫번째 두번째)
  • (왼쪽 오른쪽)
  • (차, cdr)
  • (푸, 바)
  • 기타

거의 언급되지 않은 한 가지 큰 문제는 페어와 프리미티브의 관계입니다. 당신은 경우 (int x, int y)로 이것을 나타내는 2 차원 공간의 점을 나타내는 자료 Pair<Integer, Integer>소비하는 세 개의 객체 대신 두 개의 32 비트 단어를. 또한 이러한 객체는 힙에 상주해야하며 GC 오버 헤드가 발생합니다.

스트림과 마찬가지로 페어에 대한 기본 전문화가 반드시 필요한 것 같습니다. 우리는보고 싶습니까?

Pair
ObjIntPair
ObjLongPair
ObjDoublePair
IntObjPair
IntIntPair
IntLongPair
IntDoublePair
LongObjPair
LongIntPair
LongLongPair
LongDoublePair
DoubleObjPair
DoubleIntPair
DoubleLongPair
DoubleDoublePair

심지어 IntIntPair힙에 하나의 객체가 여전히 필요합니다.

물론 이것들은 java.util.functionJava SE 8 의 패키지에서 기능적 인터페이스의 확산을 연상시킵니다. 만약 부풀린 API를 원하지 않는다면, 어떤 API를 사용하지 않겠습니까? 이것으로는 충분하지 않으며, 전문화 Boolean도 추가해야 한다고 주장 할 수 있습니다 .

내 생각에 Java가 오래 전에 Pair 클래스를 추가했다면 단순하거나 단순 해졌으며 지금 우리가 계획하고있는 많은 유스 케이스를 만족시키지 못했을 것입니다. JDK 1.0 시간대에 Pair가 추가 되었다면, 아마도 변경 가능했을 것입니다! (java.util.Date를보십시오.) 사람들이 그것에 만족했을까요? 내 생각에 Java에 Pair 클래스가 있다면 실제로 유용하지는 않지만 모든 사람들이 여전히 자신의 요구를 충족시키기 위해 자신의 롤링을 수행 할 것이며 외부 라이브러리에는 다양한 Pair 및 Tuple 구현이있을 것입니다. 사람들은 여전히 ​​Java의 Pair 클래스를 수정하는 방법에 대해 논쟁하고 있습니다. 다시 말해, 오늘날 우리와 같은 장소에 있습니다.

한편, 일부 문제는 근본적인 문제를 해결하기 위해 진행 중이며, 이는 값 유형 에 대한 JVM (및 결국 Java 언어)에서 더 잘 지원됩니다 . 이 Value of States 문서를 참조하십시오 . 이것은 예비적이고 추론적인 작업이며 JVM 관점의 문제 만 다루지 만 이미 그 뒤에 상당한 생각이 있습니다. 물론 이것이 Java 9에 들어가거나 어느 곳에 나 들어갈 것이라는 보장은 없지만이 주제에 대한 현재의 사고 방향을 보여줍니다.


답변

이 내장 클래스를 살펴볼 수 있습니다.


답변

슬프게도 Java 8은 쌍이나 튜플을 도입하지 않았습니다. 당신은 항상 사용할 수 있습니다 org.apache.commons.lang3.tuple (물론 개인적으로 자바 (8)와 함께 사용을 할 수있는) 또는 당신은 당신의 자신의 래퍼를 생성 할 수 있습니다. 또는지도를 사용하십시오. 또는 링크 된 해당 질문에 대한 대답 에 설명 된 것과 같은 것들 .


업데이트 : JDK 14는 미리보기 기능으로 레코드 를 소개 합니다. 이것들은 튜플이 아니지만 많은 동일한 문제를 저장하는 데 사용될 수 있습니다. 위의 특정 예에서 다음과 같이 보일 수 있습니다.

public class Jdk14Example {
    record CountForIndex(int index, long count) {}

    public static void main(String[] args) {
        boolean [][] directed_acyclic_graph = new boolean[][]{
                {false,  true, false,  true, false,  true},
                {false, false, false,  true, false,  true},
                {false, false, false,  true, false,  true},
                {false, false, false, false, false,  true},
                {false, false, false, false, false,  true},
                {false, false, false, false, false, false}
        };

        System.out.println(
                IntStream.range(0, directed_acyclic_graph.length)
                        .parallel()
                        .mapToObj(i -> {
                            long count = IntStream.range(0, directed_acyclic_graph[i].length)
                                            .filter(j -> directed_acyclic_graph[j][i])
                                            .count();
                            return new CountForIndex(i, count);
                        }
                        )
                        .filter(n -> n.count == 0)
                        .collect(() -> new ArrayList<CountForIndex>(), (c, e) -> c.add(e), (c1, c2) -> c1.addAll(c2))
        );
    }
}

플래그를 사용하여 JDK 14 (작성 당시의 초기 액세스 빌드)로 컴파일하고 실행 --enable-preview하면 다음 결과가 나타납니다.

[CountForIndex[index=0, count=0], CountForIndex[index=2, count=0], CountForIndex[index=4, count=0]]


답변

전체 예제는 어떤 종류의 페어 구조를 사용하지 않고도 해결할 수 있습니다. 핵심은 열 색인을 false해당 열의 항목 수에 맵핑하는 대신 술어가 전체 열을 점검하여 열 색인을 필터링하는 것입니다 .

이를 수행하는 코드는 다음과 같습니다.

    System.out.println(
        IntStream.range(0, acyclic_graph.length)
            .filter(i -> IntStream.range(0, acyclic_graph.length)
                                  .noneMatch(j -> acyclic_graph[j][i]))
            .boxed()
            .collect(toList()));

결과 [0, 2, 4]는 OP가 요청한 올바른 결과라고 생각합니다.

또한 값을 객체 로 boxed()상자에 int넣는 작업에 유의하십시오 Integer. 이것은 toList()복싱 자체를 수행하는 콜렉터 기능을 작성하는 대신 기존 콜렉터 를 사용할 수있게 합니다.


답변

Vavr (이전의 Javaslang) ( http://www.vavr.io )은 튜플 (크기 8까지)도 제공합니다. 여기의 javadoc은 다음과 같습니다 https://static.javadoc.io/io.vavr/vavr/0.9.0/io/vavr/Tuple.html .

이것은 간단한 예입니다.

Tuple2<Integer, String> entry = Tuple.of(1, "A");

Integer key = entry._1;
String value = entry._2;

왜 지금까지 JDK 자체에 간단한 종류의 튜플이 제공되지 않았습니까? 랩퍼 클래스 작성은 매일 비즈니스 인 것 같습니다.


답변

Java 9부터는 Map.Entry이전보다 쉬운 인스턴스를 작성할 수 있습니다 .

Entry<Integer, String> pair = Map.entry(1, "a");

Map.entry수정 불가능한 Entry값을 리턴 하고 널을 금지합니다.


답변

인덱스에만 관심이 있으므로 튜플에 매핑 할 필요가 없습니다. 배열에서 룩업 요소를 사용하는 필터를 작성하는 것이 어떻습니까?

     int[] value =  ...


IntStream.range(0, value.length)
            .filter(i -> value[i] > 30)  //or whatever filter you want
            .forEach(i -> System.out.println(i));