programing

Java 열거를 스트림으로 어떻게 전환합니까?

shortcode 2021. 1. 16. 20:22
반응형

Java 열거를 스트림으로 어떻게 전환합니까?


나에게 Enumeration<String>. 나는 자바 8로 유유히 그 열거 작업 할 Stream, 같은 것들을 호출 filter, map그리고 flatMap그 위에.

이 라이브러리가있는 기존 라이브러리가 있습니까? 나는 이미 Guava와 Apache Commons를 참조하고 있으므로 둘 중 하나가 이상적인 솔루션을 가지고 있다면.

또는, 설정하는 가장 / 가장 쉬운 방법은 무엇 Enumeration에이 Stream모든 것을 게으른 성격을 유지하면서는?


이 답변은 이미 다음을 만드는 솔루션을 제공 Stream합니다 Enumeration.

 public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
     return StreamSupport.stream(
         Spliterators.spliteratorUnknownSize(
             new Iterator<T>() {
                 public T next() {
                     return e.nextElement();
                 }
                 public boolean hasNext() {
                     return e.hasMoreElements();
                 }
             },
             Spliterator.ORDERED), false);
 }

터미널 작업이 시작되기 전에는 어떤 항목도 처리하지 않고 터미널 작업이 단락되면 필요한만큼만 항목을 반복 하므로 결과 Stream 다른 Stream모든 항목 만큼 지연 된다는 점을 강조해야합니다 .

그래도 개선의 여지가 있습니다. forEachRemaining모든 요소를 ​​처리하는 간단한 방법이있을 때 항상 메서드를 추가합니다 . 상기 메서드는 Stream대부분의 비 단락 작업 에 대한 구현에 의해 호출됩니다 .

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            new Iterator<T>() {
                public T next() {
                    return e.nextElement();
                }
                public boolean hasNext() {
                    return e.hasMoreElements();
                }
                public void forEachRemaining(Consumer<? super T> action) {
                    while(e.hasMoreElements()) action.accept(e.nextElement());
                }
            },
            Spliterator.ORDERED), false);
}

그러나 위의 코드는 " Iterator너무 친숙하기 때문에 사용 하는"반 패턴의 희생양입니다 . 생성 된 파일 Iterator은 새 Spliterator인터페이스 의 구현으로 래핑되며 Spliterator직접 구현하는 것보다 이점을 제공하지 않습니다 .

public static <T> Stream<T> enumerationAsStream(Enumeration<T> e) {
    return StreamSupport.stream(
        new Spliterators.AbstractSpliterator<T>(Long.MAX_VALUE, Spliterator.ORDERED) {
            public boolean tryAdvance(Consumer<? super T> action) {
                if(e.hasMoreElements()) {
                    action.accept(e.nextElement());
                    return true;
                }
                return false;
            }
            public void forEachRemaining(Consumer<? super T> action) {
                while(e.hasMoreElements()) action.accept(e.nextElement());
            }
    }, false);
}

소스 코드 수준에서이 구현은 Iterator기반 만큼 간단 하지만 a Spliterator에서 Iterator. 독자가 새 API에 대해 배우기 만하면됩니다.


바닐라 자바를 사용하지 않는 이유 :

Collections.list(enumeration).stream()...

그러나 @MicahZoltu에서 언급했듯이 Collections.list열거 형의 요소를 복사하기 위해 먼저 열거 형을 반복 하므로 열거 형의 항목 수를 고려해야 합니다 ArrayList. 거기에서 일반적인 stream방법을 사용할 수 있습니다. 이것은 많은 컬렉션 스트림 작업에 일반적이지만 열거가 너무 크면 (무한대처럼) 열거를 목록으로 변환해야하므로 여기에 설명 된 다른 접근 방식을 대신 사용해야하기 때문에 문제가 발생할 수 있습니다.


In Java 9 it is possible to convert an Enumeration to a Stream with a one-liner:

Enumeration<String> en = ... ;
Stream<String> str = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(en.asIterator(), Spliterator.ORDERED),
    false
);

(Well, it's a rather long line.)

If you're not on Java 9, you can convert the Enumeration into an Iterator manually using the technique given in Holger's answer.


According to Guava docs, you could use the Iterators.forEnumeration() method:

Enumeration<Something> enumeration = ...;

Iterator<SomeThing> iterator = Iterators.forEnumeration(enumeration);

And in this question, it is explained how to get a stream from an iterator:

Stream<Something> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.ORDERED),
    false);

In my StreamEx library there's simple method StreamEx.of(Enumeration) which does the job:

Stream<String> stream = StreamEx.of(enumeration);

Note that it not just a shortcut to the @Holger solution, but implemented in different manner. In particular, it has significantly better parallel execution characteristics compared to solutions involving Spliterators.spliteratorUnknownSize().

ReferenceURL : https://stackoverflow.com/questions/33242577/how-do-i-turn-a-java-enumeration-into-a-stream

반응형