What is a Java Stream?
Java Stream is a sequence of elements supporting the sequential and parallel aggregate operation. This example shows an aggregate operation using Stream and IntStream
int sum = widgets.stream() .filter(w -> w.getColor() == RED) .mapToInt(w -> w.getWeight()) .sum();
In this example (from Oracle Stream doc), widgets
is a Collection<Widget>. A stream of Widget
objects was created via Collection.stream()
, filter it to product a stream containing only the red widgets, and then transform it into a stream of int values representing the weight of each red widget. Finally this stream is summed to produce a total weight.
This post lists Java Streams code snippets that I find very useful
forEach
@Test public void whenIncrementSalaryForEachEmployee_thenApplyNewSalary() { empList.stream().forEach(e -> e.salaryIncrement(10.0)); assertThat(empList, contains( hasProperty("salary", equalTo(110000.0)), hasProperty("salary", equalTo(220000.0)), hasProperty("salary", equalTo(330000.0)) )); }
toArray
@Test public void whenStreamToArray_thenGetArray() { Employee[] employees = empList.stream().toArray(Employee[]::new); assertThat(empList.toArray(), equalTo(employees)); }
map
@Test public void whenMapIdToEmployees_thenGetEmployeeStream() { Integer[] empIds = { 1, 2, 3 }; List<Employee> employees = Stream.of(empIds) .map(employeeRepository::findById) .collect(Collectors.toList()); assertEquals(employees.size(), empIds.length); }
flatMap
“Flatten” a list of list to make a list
@Test public void whenFlatMapEmployeeNames_thenGetNameStream() { List<List<String>> namesNested = Arrays.asList( Arrays.asList("Jeff", "Bezos"), Arrays.asList("Bill", "Gates"), List<String> namesFlatStream = namesNested.stream() .flatMap(Collection::stream) .collect(Collectors.toList()); assertEquals(namesFlatStream.size(), namesNested.size() * 2); }
toMap
Collect elements to a map
/** Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper) **/ public Map<String, String> listToMap(List<Book> books) { return books.stream().collect(Collectors.toMap(Book::getIsbn, Book::getName)); }
toMap with duplicate keys
Collect elements to a map but these elements contain duplicate keys
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper, Function<? super T, ? extends U> valueMapper, BinaryOperator<U> mergeFunction) public Map<Integer, Book> listToMapWithDupKey(List<Book> books) { return books.stream().collect(Collectors.toMap(Book::getReleaseYear, Function.identity(), (existing, replacement) -> existing)); }
peek
@Test public void whenIncrementSalaryUsingPeek_thenApplyNewSalary() { Employee[] arrayOfEmps = { new Employee(1, "Jeff Bezos", 100000.0), new Employee(2, "Bill Gates", 200000.0), }; List<Employee> empList = Arrays.asList(arrayOfEmps); empList.stream() .peek(e -> e.salaryIncrement(10.0)) .peek(System.out::println) .collect(Collectors.toList()); assertThat(empList, contains( hasProperty("salary", equalTo(110000.0)), hasProperty("salary", equalTo(220000.0)), )); }
filter
@Test public void whenFilterEmployees_thenGetFilteredStream() { Integer[] empIds = { 1, 2, 3, 4 }; List<Employee> employees = Stream.of(empIds) .map(employeeRepository::findById) .filter(e -> e != null) .filter(e -> e.getSalary() > 200000) .collect(Collectors.toList()); assertEquals(Arrays.asList(arrayOfEmps[2]), employees); }
skip first 3 then limit to 5 elements
@Test public void whenLimitInfiniteStream_thenGetFiniteElements() { Stream<Integer> infiniteStream = Stream.iterate(2, i -> i * 2); List<Integer> collect = infiniteStream .skip(3) .limit(5) .collect(Collectors.toList()); assertEquals(collect, Arrays.asList(16, 32, 64, 128, 256)); }
sorted
@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"); }
min
@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)); }
distinct
@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)); }
max and 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)); }
allMatch, anyMatch, and nonMatch
@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); }
mapToInt
@Test public void whenFindMaxOnIntStream_thenGetMaxInteger() { Integer latestEmpId = empList.stream() .mapToInt(Employee::getId) .max() .orElseThrow(NoSuchElementException::new); assertEquals(latestEmpId, new Integer(3)); }
reduce
@Test public void whenApplyReduceOnStream_thenGetValue() { Double sumSal = empList.stream() .map(Employee::getSalary) .reduce(0.0, Double::sum); assertEquals(sumSal, new Double(600000)); }
mapToDouble
@Test public void whenApplySumOnIntStream_thenGetSum() { Double avgSal = empList.stream() .mapToDouble(Employee::getSalary) .average() .orElseThrow(NoSuchElementException::new); assertEquals(avgSal, new Double(200000)); }
collect joining
@Test public void whenCollectByJoining_thenGetJoinedString() { String empNames = empList.stream() .map(Employee::getName) .collect(Collectors.joining(", ")) .toString(); assertEquals(empNames, "Jeff Bezos, Bill Gates, Mark Zuckerberg"); }
collect toSet
@Test public void whenCollectBySet_thenGetSet() { Set<String> empNames = empList.stream() .map(Employee::getName) .collect(Collectors.toSet()); assertEquals(empNames.size(), 3); }
collect toCollection
@Test public void whenToVectorCollection_thenGetVector() { Vector<String> empNames = empList.stream() .map(Employee::getName) .collect(Collectors.toCollection(Vector::new)); assertEquals(empNames.size(), 3); }
collect toList
@Test public void whenCollectStreamToList_thenGetList() { List<Employee> employees = empList.stream().collect(Collectors.toList()); assertEquals(empList, employees); }
summaryStatistics and mapToDouble
@Test public void whenApplySummaryStatistics_thenGetBasicStats() { DoubleSummaryStatistics stats = empList.stream() .mapToDouble(Employee::getSalary) .summaryStatistics(); assertEquals(stats.getCount(), 3); assertEquals(stats.getSum(), 600000.0, 0); assertEquals(stats.getMin(), 100000.0, 0); assertEquals(stats.getMax(), 300000.0, 0); assertEquals(stats.getAverage(), 200000.0, 0); }
summarizeDouble
@Test public void whenApplySummarizing_thenGetBasicStats() { DoubleSummaryStatistics stats = empList.stream() .collect(Collectors.summarizingDouble(Employee::getSalary)); assertEquals(stats.getCount(), 3); assertEquals(stats.getSum(), 600000.0, 0); assertEquals(stats.getMin(), 100000.0, 0); assertEquals(stats.getMax(), 300000.0, 0); assertEquals(stats.getAverage(), 200000.0, 0); }
partitioningBy
@Test public void whenStreamPartition_thenGetMap() { List<Integer> intList = Arrays.asList(2, 4, 5, 6, 8); Map<Boolean, List<Integer>> isEven = intList.stream().collect( Collectors.partitioningBy(i -> i % 2 == 0)); assertEquals(isEven.get(true).size(), 4); assertEquals(isEven.get(false).size(), 1); }
groupBy
@Test public void whenStreamGroupingBy_thenGetMap() { Map<Character, List<Employee>> groupByAlphabet = empList.stream().collect( Collectors.groupingBy(e -> new Character(e.getName().charAt(0)))); assertEquals(groupByAlphabet.get('B').get(0).getName(), "Bill Gates"); assertEquals(groupByAlphabet.get('J').get(0).getName(), "Jeff Bezos"); assertEquals(groupByAlphabet.get('M').get(0).getName(), "Mark Zuckerberg"); }