sorted
Let’s start with the sorted() operation—this sorts the stream elements based on the comparator passed we pass into it.
For example, we can sort Employees based on their names:
@Test public void whenSortStream_thenGetSortedStream() { List<Employee> employees = empList.stream() .sorted((e1, e2) -> e1.getName().compareTo(e2.getName())) .collect(Collectors.toList()); assertEquals(employees.get(0).getName(), "Bill Gates"); assertEquals(employees.get(1).getName(), "Jeff Bezos"); assertEquals(employees.get(2).getName(), "Mark Zuckerberg"); }
Note that short-circuiting will not be applied for sorted().
This means, in the example above, even if we had used findFirst() after the sorted(), the sorting of all the elements is done before applying the findFirst(). This happens because the operation cannot know what the first element is until the entire stream is sorted.
min and max
As the names suggest, min() and max() return the minimum and maximum element in the stream respectively, based on a comparator. They return an Optional since a result may or may not exist (due to, say, filtering):
@Test public void whenFindMin_thenGetMinElementFromStream() { Employee firstEmp = empList.stream() .min((e1, e2) -> e1.getId() - e2.getId()) .orElseThrow(NoSuchElementException::new); assertEquals(firstEmp.getId(), new Integer(1)); }
We can also avoid defining the comparison logic by using Comparator.comparing():
@Test public void whenFindMax_thenGetMaxElementFromStream() { Employee maxSalEmp = empList.stream() .max(Comparator.comparing(Employee::getSalary)) .orElseThrow(NoSuchElementException::new); assertEquals(maxSalEmp.getSalary(), new Double(300000.0)); }
distinct
distinct() does not take any argument and returns the distinct elements in the stream, eliminating duplicates. It uses the equals() method of the elements to decide whether two elements are equal or not:
@Test public void whenApplyDistinct_thenRemoveDuplicatesFromStream() { List<Integer> intList = Arrays.asList(2, 5, 3, 2, 4, 3); List<Integer> distinctIntList = intList.stream().distinct().collect(Collectors.toList()); assertEquals(distinctIntList, Arrays.asList(2, 5, 3, 4)); }
allMatch, anyMatch, and noneMatch
These operations all take a predicate and return a boolean. Short-circuiting is applied and processing is stopped as soon as the answer is determined:
@Test public void whenApplyMatch_thenReturnBoolean() { List<Integer> intList = Arrays.asList(2, 4, 5, 6, 8); boolean allEven = intList.stream().allMatch(i -> i % 2 == 0); boolean oneEven = intList.stream().anyMatch(i -> i % 2 == 0); boolean noneMultipleOfThree = intList.stream().noneMatch(i -> i % 3 == 0); assertEquals(allEven, false); assertEquals(oneEven, true); assertEquals(noneMultipleOfThree, false); }
allMatch() checks if the predicate is true for all the elements in the stream. Here, it returns false as soon as it encounters 5, which is not divisible by 2.
anyMatch() checks if the predicate is true for any one element in the stream. Here, again short-circuiting is applied and true is returned immediately after the first element.
noneMatch() checks if no elements are matching the predicate. Here, it simply returns false as soon as it encounters 6, which is divisible by 3.
Java Stream Specializations
From what we discussed so far, a Stream is a stream of object references. However, there are also the IntStream, LongStream, and DoubleStream—which are primitive specializations for int, long and double respectively. These are quite convenient when dealing with a lot of numerical primitives.
These specialized streams do not extend Stream but extend BaseStream on top of which Stream is also built.
As a consequence, not all operations supported by Stream are present in these stream implementations. For example, the standard min() and max() take a comparator, whereas the specialized streams do not.
Creation
The most common way of creating an IntStream is to call mapToInt() on an existing stream:
@Test public void whenFindMaxOnIntStream_thenGetMaxInteger() { Integer latestEmpId = empList.stream() .mapToInt(Employee::getId) .max() .orElseThrow(NoSuchElementException::new); assertEquals(latestEmpId, new Integer(3)); }
Here, we start with a Stream<Employee> and get an IntStream by supplying the Employee::getId to mapToInt. Finally, we call max() which returns the highest integer.
We can also use IntStream.of() for creating the IntStream:
IntStream.of(1, 2, 3);
or IntStream.range():
IntStream.range(10, 20)
This creates IntStream of numbers 10 to 19.
One important distinction to note before we move on to the next topic:
Stream.of(1, 2, 3)
This returns a Stream<Integer> and not IntStream.
Similarly, using map() instead of mapToInt() returns a Stream<Integer> and not an IntStream.:
empList.stream().map(Employee::getId);
Specialized Operations
Specialized streams provide additional operations as compared to the standard Stream—which are quite convenient when dealing with numbers.
For example sum(), average(), range() etc.:
@Test public void whenApplySumOnIntStream_thenGetSum() { Double avgSal = empList.stream() .mapToDouble(Employee::getSalary) .average() .orElseThrow(NoSuchElementException::new); assertEquals(avgSal, new Double(200000)); }
Reduction Operations
A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation. We already saw a few reduction operations like findFirst(), min() and max().
Let’s see the general-purpose reduce() operation in action.
reduce
The most common form of reduce() is:
T reduce(T identity, BinaryOperator<T> accumulator)
Here, identity is the starting value and accumulator is the binary operation we repeatedly apply.
For example:
@Test public void whenApplyReduceOnStream_thenGetValue() { Double sumSal = empList.stream() .map(Employee::getSalary) .reduce(0.0, Double::sum); assertEquals(sumSal, new Double(600000)); }
Here, we start with the initial value of 0 and repeatedly apply Double::sum() on elements of the stream. Effectively we’ve implemented the DoubleStream.sum() by applying reduce() on Stream.
Post a Comment