(잠재적으로 무한)을 제한하는 Java 8 스트림 작업이 있습니까? Stream
첫 번째 요소가 술어와 일치하지 않을 때까지 있습니까?
Java 9에서는 takeWhile
아래 예와 같이 10 미만의 모든 숫자를 인쇄 할 수 있습니다 .
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
Java 8에는 그러한 작업이 없으므로 일반적인 방법으로 구현하는 가장 좋은 방법은 무엇입니까?
답변
이러한 작업 은 Java 8 로 가능 해야 Stream
하지만 효율적으로 수행 할 수있는 것은 아닙니다. 예를 들어, 요소를 순서대로 살펴보아야하므로 이러한 작업을 병렬화 할 필요는 없습니다.
API는이를 수행하는 쉬운 방법을 제공하지 않지만 아마도 가장 간단한 방법은을 수행 하고 “취약”구현을 갖도록 Stream.iterator()
랩한 다음 a Iterator
로 이동 Spliterator
하는 것 Stream
입니다. 또는 아마도이 Spliterator
구현에서 더 이상 나눌 수는 없지만를 감싸십시오 .
다음의 검증되지 않은 구현의 takeWhile
A의는 Spliterator
:
static <T> Spliterator<T> takeWhile(
Spliterator<T> splitr, Predicate<? super T> predicate) {
return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
boolean stillGoing = true;
@Override public boolean tryAdvance(Consumer<? super T> consumer) {
if (stillGoing) {
boolean hadNext = splitr.tryAdvance(elem -> {
if (predicate.test(elem)) {
consumer.accept(elem);
} else {
stillGoing = false;
}
});
return hadNext && stillGoing;
}
return false;
}
};
}
static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}
답변
운영 takeWhile
및 dropWhile
JDK 9. 예제 코드에 추가되었습니다
IntStream
.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
JDK 9에서 컴파일하고 실행할 때 예상대로 정확하게 작동합니다.
JDK 9가 릴리스되었습니다. http://jdk.java.net/9/ 에서 다운로드 할 수 있습니다.
답변
allMatch()
는 단락 기능이므로 처리를 중지하는 데 사용할 수 있습니다. 가장 큰 단점은 테스트를 두 번 수행해야한다는 것입니다. 한 번 처리해야하는지 확인하고 계속 진행해야하는지 확인해야합니다.
IntStream
.iterate(1, n -> n + 1)
.peek(n->{if (n<10) System.out.println(n);})
.allMatch(n->n < 10);
답변
@StuartMarks에 대한 후속 조치로 . 내 StreamEx 라이브러리에는 takeWhile
현재 JDK-9 구현과 호환되는 작업이 있습니다. JDK-9에서 실행될 때 JDK 구현에 위임 할 것 MethodHandle.invokeExact
입니다 (실제로 빠릅니다). JDK-8에서 실행될 때는 “polyfill”구현이 사용됩니다. 따라서 내 라이브러리를 사용하면 다음과 같이 문제를 해결할 수 있습니다.
IntStreamEx.iterate(1, n -> n + 1)
.takeWhile(n -> n < 10)
.forEach(System.out::println);
답변
takeWhile
protonpack 라이브러리가 제공하는 기능 중 하나입니다 .
Stream<Integer> infiniteInts = Stream.iterate(0, i -> i + 1);
Stream<Integer> finiteInts = StreamUtils.takeWhile(infiniteInts, i -> i < 10);
assertThat(finiteInts.collect(Collectors.toList()),
hasSize(10));
답변
업데이트 : Java 9에는 Stream
이제 takeWhile 이 제공됩니다. 메소드 .
해킹이나 다른 솔루션이 필요하지 않습니다. 그냥 사용하십시오!
나는 이것이 크게 향상 될 수 있다고 확신한다 : (누군가 그것을 스레드로부터 안전하게 만들 수있다)
Stream<Integer> stream = Stream.iterate(0, n -> n + 1);
TakeWhile.stream(stream, n -> n < 10000)
.forEach(n -> System.out.print((n == 0 ? "" + n : "," + n)));
확실한 해킹은 … 우아하지는 않지만 작동하지만 ~ : D
class TakeWhile<T> implements Iterator<T> {
private final Iterator<T> iterator;
private final Predicate<T> predicate;
private volatile T next;
private volatile boolean keepGoing = true;
public TakeWhile(Stream<T> s, Predicate<T> p) {
this.iterator = s.iterator();
this.predicate = p;
}
@Override
public boolean hasNext() {
if (!keepGoing) {
return false;
}
if (next != null) {
return true;
}
if (iterator.hasNext()) {
next = iterator.next();
keepGoing = predicate.test(next);
if (!keepGoing) {
next = null;
}
}
return next != null;
}
@Override
public T next() {
if (next == null) {
if (!hasNext()) {
throw new NoSuchElementException("Sorry. Nothing for you.");
}
}
T temp = next;
next = null;
return temp;
}
public static <T> Stream<T> stream(Stream<T> s, Predicate<T> p) {
TakeWhile tw = new TakeWhile(s, p);
Spliterator split = Spliterators.spliterator(tw, Integer.MAX_VALUE, Spliterator.ORDERED);
return StreamSupport.stream(split, false);
}
}
답변
java8 + rxjava를 사용할 수 있습니다 .
import java.util.stream.IntStream;
import rx.Observable;
// Example 1)
IntStream intStream = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
.takeWhile(n ->
{
System.out.println(n);
return n < 10;
}
).subscribe() ;
// Example 2
IntStream intStream = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
.takeWhile(n -> n < 10)
.forEach( n -> System.out.println(n));