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.StreamSupport
java.util.Spliterators
java.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`