Consider:
See: https://stackoverflow.com/questions/24676877/should-i-return-a-collection-or-a-stream:
Consider a typical spring application with a DAO which has a method like following:
@Transactional
Stream<Person> getAll(){
return ...
}
Note that the method is annotated with @Transactional. In the case that the returned stream throws an exception during processing, the @Transactional has no effect. Because the stream processing is executed outside the @Transactional context (not processed in the getAll method).
Do not return streams which have (maybe hidden) processing dependencies to the context.
...filter(Objects::nonNull);
A combination of Class.isInstance and Class.cast together with Stream.filter and Stream.map results in a stream of objects with the desired type:
Stream.of("String", Integer.valueOf(1))
// reduce to a stream of Integer:
.filter(Integer.class::isInstance).map(Integer.class::cast)
Exceptions which are thrown due to intermediate operations occur when the stream is processed.
Example
public void test() {
integerStream().forEach(System.out::println);
}
private Stream<Integer> integerStream() {
try {
return Stream.of("1","noNumber","3").map(Integer::valueOf);
}
catch (Exception e) {
e.printStackTrace();
}
return Stream.empty();
}
In this case the NumberFormatException which is thrown from Integer::valueOf due to parse errors of “noNumber” is not catched from the catch block in the integerStream method. The Exception is thrown from the integerStream method.
With the help of classes
java.util.stream.StreamSupportjava.util.Spliteratorsjava.util.Iterator<Integer>one can create a stream with a limited (but unknown) number of elements.
{. code .x title=”Example code”}
Iterator<Integer> iter = new Iterator<Integer>() {
Random rand = new Random();
public boolean hasNext() {
// Iterator has a random number of elements:
return rand.nextInt(100) < 90;
}
public Integer next() {
return Integer.valueOf(rand.nextInt(100));
}
};
Stream<Integer> stream =
StreamSupport.stream(Spliterators.spliteratorUnknownSize(iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
// for details see javadoc
// https://docs.oracle.com/javase/8/docs/api/java/util/stream/StreamSupport.html
// https://docs.oracle.com/javase/8/docs/api/java/util/Spliterators.html
stream.forEach(System.out::println);
Examples:
Read lines with java.io.BufferedReader.lines() with enumeration
Via Enumeration -> Interator kann man über eine Enumeation streamen
{. code .x title=”Enumeration to Stream”}
public static <T> Stream<T> stream(Enumeration<T> enumeration) {
// https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Enumeration.html#asIterator()
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator<T>() {
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public T next() {
return enumeration.nextElement();
}
}, Spliterator.ORDERED), false);
}
{. code .x title=”Iterable to Stream”}
public static <T> Stream<T> stream(Iterable<T> iterable) {
return (iterable instanceof Collection) ? ((Collection<T>) iterable).stream()
: StreamSupport.stream(iterable.spliterator(), false);
}
{. code .x title=”Iterator to Stream”}
public static <T> Stream<T> stream(Iterator<T> iterator) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
}
Or one can use a utils class which transforms an Enumeration to an Iterator like org.springframework.util.CollectionUtils.toIterator(Enumeration<E>)
{. code .x title=”Recursive Tree Walking with Stream”}
public List<Node> getChildren() {
return ...
}
public Stream<Node> flattened() {
return Stream.concat(Stream.of(this), getChildren().stream().flatMap(Node::flattened));
}
* The call of `flatMap`