Chapter 4. Collection Operations with Lambda
4.1. Develop the code to extract data from an object using map
Applying a function to each element of a stream
Streams support the method map()
, which takes a Function
as argument.
Primitive stream specializations
Java 8 introduces three primitive specialized stream interfaces that support specialized methods (like max(), sum(), average())
to work with streams of numbers: IntStream
(rather than a Stream<Integer>
), DoubleStream
, and LongStream
.
1
2
3
4
5
6
7
8
IntStream istream = names.mapToInt(s -> s.length());
System.out.println("Max: " + istream.max().getAsInt());
// stream has already been operated upon or closed
// following if uncommented will throw an Exception
// System.out.println("Total: " + istream.count());
4.2. Search for data using search methods including: findFirst, findAny, anyMatch, allMatch, noneMatch.
Methods on Stream
-
findFirst
- Finding the first elementOptional<T> findFirst();
-
findAny
- Finding an element - findAny Gives a more flexible alternative to findFirst(). Can be used in a parallel stream.Optional<T> findAny();
-
anyMatch
- Checking to see if a predicate matches at least one element Is there an element in the stream matching the given predicate?boolean anyMatch(Predicate<? super T> predicate);
-
allMatch
- Checking to see if a predicate matches all elementsboolean allMatch(Predicate<? super T> predicate);
-
noneMatch
- Checking to see if a predicate does not matche any element -boolean noneMatch(Predicate<? super T> predicate);
Remember the method signatures:
All findXxx()
methods have no arguments and return Optional
.
All xxxMatch(...)
methods accept a Predicate
and return a boolean
primitive.
All the above are short circuit
operations. If results match or dont match, they will come out without processing the whole stream.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private static void findFirst() {
List<Employee> employees = Arrays.asList(new Employee("Jack"), new Employee("Jill"), new Employee("Jiane"));
Stream<Employee> emps = employees.stream();
Optional<Employee> result = emps.filter(s -> s.getName().contains("i")).findFirst();
System.out.println("findFirst Result = " + result.get());
}
private static void allMatch() {
List<Employee> employees = Arrays.asList(new Employee("Jack"), new Employee("Jill"), new Employee("Jiane"));
Stream<Employee> emps = employees.stream();
boolean result = emps.allMatch(s -> s.getName().startsWith("J"));
System.out.println("allMatch Result = " + result);
}
private static void noneMatch() {
List<Employee> employees = Arrays.asList(new Employee("Jack"), new Employee("Jill"), new Employee("Jiane"));
Stream<Employee> emps = employees.stream();
boolean result = emps.noneMatch(s -> s.getName().startsWith("K"));
System.out.println("noneMatch Result = " + result);
}
Output
findFirst Result = Jill
allMatch Result = true
noneMatch Result = true
4.3. Describe the unique characteristics of the Optional classes
A java.util.Optional<T>
object is either a wrapper for an Object of type T or a wrapper for no object.
Creation
The Optional class provides several instance methods to read the value contained by an Optional instance.
Optional.get()
is the simplest but also the least safe of these methods.
It returns the wrapped value if present but throws a NoSuchElementException
otherwise.
For this reason, using this method is almost always a bad idea unless you are really sure the optional contains a value.
Optional.orElse(T other)
it allows you to provide a default value for when the optional does not contain a value.
NOTE: the other value may be null.
Optional.orElseGet(Supplier<? extends T> other)
is the lazy counterpart of the orElse method,
because the supplier is invoked only if the optional contains no value.
You should use this method either when the default value is time-consuming to create or you want to be sure this is done only
if the optional is empty.
Optional.orElseThrow(Supplier<? extends X> exceptionSupplier)
is similar to the get() method in that it throws an exception
when the optional is empty, but in this case it allows you to choose the type of exception that you want to throw.
Optional.ifPresent(Consumer<? super T> consumer)
lets you execute the action given as argument if a value is present; otherwise no action is taken.
Optional.isPresent()
returns true if the Optional contains a value, false otherwise.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
Optional<String> opt1 = Optional.of("Hello");
String s = opt1.get();
System.out.println(opt1.isPresent() + " " + s);
Optional<String> opt2 = Optional.empty();
System.out.println("Value or default: " + opt2.orElse("Default"));
// With Supplier
System.out.println("Value or default: " + opt2.orElseGet(() -> "Some default"));
// Print only if opt1 has a value, Takes in a Consumer
opt1.ifPresent(System.out::println);
// Throws NPE
Optional<String> optNull = Optional.of(null);
}
Output
true Hello
Value or default: Default
Value or default: Some default
Hello
Exception in thread "main" java.lang.NullPointerException
4.4. Perform calculations using methods: count, max, min, average, sum
Stream Data Methods
Stream.min(...) and Stream.max(...)
Optional<T> min(Comparator<? super T> comp);
Optional<T> max(Comparator<? super T> comp);
Stream.count()
long count()
Note that min
and max
return an Optional
. Also average
and sum
apply to primitive streams only
Primitive streams
IntStream
- also used for short, char, byte, and boolean
LongStream
, and
DoubleStream
also for float
Stream of objects can be mapped using mapToInt
, mapToLong
, or mapToDouble
methods.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static void primitiveStreams() {
List<Integer> list = Arrays.asList(20, 2, 72, 991, 100, -11);
IntStream is = list.stream().mapToInt(t -> t);
System.out.println("Max = " + is.max());
IntStream is2 = list.stream().mapToInt(t -> t);
System.out.println("Min = " + is2.min());
IntStream is3 = list.stream().mapToInt(t -> t);
System.out.println("Sum = " + is3.sum());
IntStream is4 = list.stream().mapToInt(t -> t);
System.out.println("Avg = " + is4.average().getAsDouble());
}
Output
Max = OptionalInt[991]
Min = OptionalInt[-11]
Sum = 1174
Avg = 195.66666666666666
4.5. Sort a collection using lambda expressions
sorted()
- This is a stateful intermediate operation.
Sorts the input stream that has elements of type Comparable(if not ClassCastException
is thrown ) in natural order.
Comparators can also be chained using
.sorted(c1.thenComparing(c2))
where
Comparator<Employee> c1 = Comparator.comparing(e -> e.name.length());
Comparator<Employee> c2 = (e1, e2) -> e1.name.compareTo(e2.name);
4.6. Save results to a collection by using the collect method and Collector class; including methods such as averagingDouble, groupingBy, joining, partitioningBy
-
joining
- Returns a Collector that concatenates the input elements into a String
-
groupingBy
- Create a group of values
Example:
-
partitioningBy
: Returns a Collector which partitions the input elements according to a Predicate, and organizes them into a Map<Boolean, List>.
Example:
-
averagingDouble
:
You should know all the overloaded methods given here.
Next Chapter - Parallel Streams