Working With Stream Flashcards
In this chapter, you’ll have an extensive look at the various operations supported by the Streams API.
Filtering unique elements
Streams also support a method called distinct that returns a stream with unique elements
(according to the implementation of the hashcode and equals methods of the
objects produced by the stream).
use of TAKEWHILE ?
The takeWhile operation is here to rescue you! It lets you slice any stream (even an infinite stream as you will
learn later) using a predicate.
But thankfully, it stops once it has found an element that fails to match.
Best over filter when collections are already sorted.
Truncating a stream?
Streams support the limit(n) method, which returns another stream that’s no longer than a given size. The requested size is passed as argument to limit.
Skipping elements
Streams support the skip(n) method to return a stream that discards the first n elements.
If the stream has fewer than n elements, an empty stream is returned. Note that
limit(n) and skip(n) are complementary!
How could you return a list of all the unique characters for a list of words? For example, given the list of words [“Hello,” “World”] you’d like to
return the list [“H,” “e,” “l,” “o,” “W,” “r,” “d”].
List uniqueCharacters = words.stream() .map(word -> word.split("")) .flatMap(Arrays::stream) .distinct() .collect(toList());
Given two lists of numbers, how would you return all pairs of numbers? For example,
given a list [1, 2, 3] and a list [3, 4] you should return [(1, 3), (1, 4), (2, 3), (2, 4),
(3, 3), (3, 4)]. For simplicity, you can represent a pair as an array with two elements.
You could use two maps to iterate on the two lists and generate the pairs. But this
would return a Stream>. What you need to do is flatten the
generated streams to result in a Stream. This is what flatMap is for:
List numbers1 = Arrays.asList(1, 2, 3); List numbers2 = Arrays.asList(3, 4); List pairs = numbers1.stream() .flatMap(i -> numbers2.stream() .map(j -> new int[]{i, j}) ) .collect(toList());
Short-circuiting evaluation?
Some operations don’t need to process the whole stream to produce a result. For example, say you need to evaluate a large boolean expression chained with and operators. You need only find out that one expression is false to deduce that the
whole expression will return false, no matter how long the expression is; there’s no need to evaluate the entire expression. This is what short-circuiting refers to.
In relation to streams, certain operations such as allMatch, noneMatch, findFirst,
and findAny don’t need to process the whole stream to produce a result. As soon as an element is found, a result can be produced. Similarly, limit is also a shortcircuiting operation. The operation only needs to create a stream of a given size without
processing all the elements in the stream. Such operations are useful (for example,
when you need to deal with streams of infinite size, because they can turn an
infinite stream into a stream of finite size).
Finding any element
The findAny method returns an arbitrary element of the current stream. It can be used in conjunction with other stream operations.
Optional dish =
menu.stream()
.filter(Dish::isVegetarian)
.findAny();
When to use findFirst and findAny?
You may wonder why we have both findFirst and findAny. The answer is parallelism.
Finding the first element is more constraining in parallel. If you don’t care about which element is returned, use findAny because it’s less constraining when using
parallel streams.
How would you count the number of dishes in a stream using the map and reduce
methods?
int count = menu.stream()
.map(d -> 1)
.reduce(0, (a, b) -> a + b);
What are Primitive stream specializations?
Java 8 introduces three primitive specialized stream interfaces to tackle this issue, Int-
Stream, DoubleStream, and LongStream, which respectively specialize the elements of
a stream to be int, long, and double—and thereby avoid hidden boxing costs.
MAPPING TO A NUMERIC STREAM
int calories = menu.stream()
.mapToInt(Dish::getCalories)
.sum();
IntStream also supports other convenience methods such as max, min, and average.
CONVERTING BACK TO A STREAM OF OBJECTS
To convert from a
primitive stream to a general stream (each int will be boxed to an Integer) you can
use the method boxed, as follows:
IntStream intStream = menu.stream().mapToInt(Dish::getCalories);
Stream stream = intStream.boxed();
Pythagorean triple? for e.g (5, 12, 13)
Stream pythagoreanTriples = IntStream.rangeClosed(1, 100).boxed() .flatMap(a -> IntStream.rangeClosed(a, 100) .filter(b -> Math.sqrt(a*a + b*b) % 1 == 0) .mapToObj(b -> new int[]{a, b, (int)Math.sqrt(a * a + b * b)}) );
Streams from values
Stream stream = Stream.of(“Modern “, “Java “, “In “, “Action”);