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");
}