Slide navigation: Forward with space bar, → arrow key, or PgDn. Backwards with ← or PgUp.

Copyright © Cay S. Horstmann 2016
List<String> words = ...;
int count = 0;
for (String w : words) {
if (w.length() > 12) count++;
}
long count = words.stream() .filter(w -> w.length() > 12) .count();
import java.util.stream.*;
import java.nio.file.*;
Stream<String> words = Files.lines(Paths.get("/usr/share/dict/words"));
long count = words.filter(w -> w.length() > 12).count();
filter) or a result (count).Stream<T> stream = collection.stream();
Stream<T> stream = Stream.of(array);
Stream.of is a varargs method:
Stream<String> song = Stream.of("gently", "down", "the", "stream");
Stream.empty makes an empty stream:Stream<String> silence = Stream.empty();
Stream<String> echos = Stream.generate(() -> "Echo"); Stream<Double> randoms = Stream.generate(Math::random);
Stream.iterate.f that is iteratively applied:
Stream<BigInteger> integers = Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE));
seed, f(seed), f(f(seed)), and so on.Stream<String> lines = Files.lines(path);
try-with-resources to make sure file is closed:
try (Stream<String> lines = Files.lines(path)) {
Process lines
}String contents = ...;
Pattern pattern = Pattern.compile("\\s+"); // Break at white space
Stream<String> words = pattern.splitAsStream(contents);

Scanner.tokens, Matcher.results, ServiceLoader.stream, LocalDate.datesUntil, StackWalker.walk, ClassLoader.resources, Process.children/descendants, Catalog.catalogs, DriverManager.driversScanner.tokens gets a stream of tokens, similar to Pattern.splitAsStream from Java 8:
Stream<String> tokens = new Scanner(path).useDelimiter("\\s*,\\s*").tokens(); BigInteger limit = new BigInteger("10000000");
Stream<BigInteger> integers
= Stream.iterate(BigInteger.ZERO,
n -> n.compareTo(limit) < 0,
n -> n.add(BigInteger.ONE));filter yields a new stream:
List<String> words = ...; Stream<String> longWords = words.stream().filter(w -> w.length() > 12);
Predicate<T>map to transform all stream elements:
Stream<String> lowercaseWords = words.stream().map(String::toLowerCase); Stream<String> firstLetters = words.stream().map(s -> s.substring(0, 1));
flatMapmap takes a Function<T, U> and yields a Stream<U>Stream:
public static Stream<String> letters(String s)
// letters("boat") is a Stream ["b", "o", "a", "t"]letters to a Stream<String>, you get a Stream<Stream<String>>:
[... ["y", "o", "u", "r"], ["b", "o", "a", "t"], ...]
Stream<String>, use flatMap:
Stream<String> flatResult = words.stream().flatMap(w -> letters(w))
// Yields [... "y", "o", "u", "r", "b", "o", "a", "t",
...]
Stream-valued functions.
flatMap to compose Optional-valued functionslimit returns a new stream that ends after a given number of elements (or earlier if the stream is shorter):
Stream<Double> randoms = Stream.generate(Math::random).limit(100);
skip does the opposite:
Stream<String> words = Stream.of(contents.split("\\PL+")).skip(1);concat concatenates two streams:
Stream<String> combined = Stream.concat(letters("Hello"), letters("World"));
// Yields the stream ["H", "e", "l", "l", "o", "W", "o", "r", "l", "d"]distinct suppresses duplicates (not necessarily adjacent):
Stream<String> uniqueWords
= Stream.of("merrily", "merrily", "merrily", "gently").distinct();
// Only one "merrily" is retainedsorted yields a stream of the elements in sorted order:
Stream<String> longestFirst =
words.stream().sorted(Comparator.comparing(String::length).reversed());peek yields a stream with the same elements at the original, calling a function on each retrieved element:
Object[] powers = Stream.iterate(1.0, p -> p * 2)
.peek(e -> System.out.println("Fetching " + e))
.limit(20).toArray();
long count = words.stream().filter(w -> w.length() > 12).count();
max/min methods return the largest or smallest stream element:
Optional<String> largest = words.max(String::compareToIgnoreCase);
Optional because the stream might have been empty—see next slide.findFirst yields the first element:
Optional<String> startsWithQ = words.filter(s -> s.startsWith("Q")).findFirst();
findAny instead on a parallel stream.anyMatch yields true if a predicate has a match:
boolean aWordStartsWithQ = words.anyMatch(s -> s.startsWith("Q"));allMatch and noneMatch.import java.util.stream.*;
import java.nio.file.*;
Stream<String> words() throws IOException {
return Files.lines(Paths.get("/usr/share/dict/words"));
}
words().filter(w -> w.length() > 12).max(String::compareToIgnoreCase);
words().filter(s -> s.startsWith("Qu")).findFirst();
Optional TypeOptional<T> wraps an object of type T or no object.null”.String result = optionalString.orElse("");
String result = optionalString.orElseGet(() -> System.getProperty("user.dir"));
String result = optionalString.orElseThrow(IllegalStateException::new);optionalValue.ifPresent(results::add); Optional<Boolean> added = optionalValue.map(results::add);
get:
Optional<T> optionalValue = ...; optionalValue.get().someMethod()
T value = ...; value.someMethod(); // NPE ifvalueisnull
if (optionalValue.isPresent()) optionalValue.get().someMethod();
if (value != null) value.someMethod();
Optional, produce a wrapped value if there is a result:
public static Optional<Double> inverse(Double x) {
if (x != 0) return Optional.of(1 / x);Optional.empty() if there is no result:
else return Optional.empty(); }
ofNullable turns “object or null” into an Optional:
obj = find(queryData);
return Optional.ofNullable(obj);
// Optional.of(obj) if obj not null, or Optional.empty()flatMapf yields an Optional<T> and T has a method g yielding an Optional<U>.f and g by calling s.f().g()? f returns an Optional<T>, not a T.flatMap instead:
Optional<U> result = s.f().flatMap(T::g);
s.f() is Optional.of(t) and t.g() is Optional(r), that's the result.s.f() is Optional.of(t) and t.g() is empty, the result is empty.s.f() is empty, the result is empty.flatMap on streams if you think of an Optional as a stream of size zero or one.
HttpClient.authenticator/cookieManager/proxy/sslParameters, ServiceLoader.findFirst, Runtime.Version.build/pre/post, ProcessHandle.of, ProcessHandle.Info.command/commandLine/arguments/
startInstant/totalCpuDuration/userOptional class.optionalValue.ifPresentOrElse(System.out::println, // Consumer
() -> Runtime.exec("rm -rf /home")); // RunnableOptional<Double> result = squareRoot(x).or(
() -> inverse(x)) // Another Optional, supplied lazily
squareRoot(x) nonempty? If so, it is the answer.inverse(x). Optional Java 9 NewsStream<T> stream()Yields a stream of length 0 or 1.
Stream.flatMap to drop empty results:
class Person
{
public Optional<String> nickname() // Not everyone has one
...
}
Stream<String> nicknames = people.map(Person::nickname)
.flatMap(Optional::stream);String contents = optionalString.orElseThrow();
getOptional Cheat Sheetdata = opt.orElse(defaultValue); data = opt.orElseGet(() -> ...); data = opt.orElseThrow(SomeException::new); data = opt.orElseThrow(); // same asget, throwsNoSuchElementException, Java 10
opt.ifPresent(value -> ...); opt.ifPresentOrElse(value -> ..., () -> ...); // Java 9
anotherOpt = opt.filter(value -> ...).map(value -> ...).or(() -> ...);
Optional Code SmellsOptional should never be null!Optional type.
null is manageable inside a class.Optional type.
Optional intended as return type.List of Optional values or a Map with Optional keys is dubious.
List<Optional<String>>, just have List<String>Optional to make a null check:
Optional.ofNullable(result).ifPresentOrElse(...); // Way too complex
Iterator<T> iter = stream.iterate()stream.forEach(System.out::println);
toArray yields an array of stream elements.String[] result = stream.toArray(String[]::new);
// stream.toArray() has type Object[]collect method passes stream elements to a Collector.Collectors has many factory methods for collectors:
List<String> result = stream.collect(Collectors.toList()); Set<String> result = stream.collect(Collectors.toSet());
TreeSet<String> result = stream.collect(Collectors.toCollection(TreeSet::new));
String result = stream.collect(Collectors.joining(", "));summarizingInt, summarizingLong, summarizingDouble yield object with methods sum, average, max, min:
IntSummaryStatistics summary = stream.collect(Collectors.summarizingInt(String::length)); double averageWordLength = summary.getAverage(); int maxWordLength = summary.getMax();
Collectors.toMap:
Map<Integer, String> idToName = people.collect(
Collectors.toMap(Person::getId, Person::getName));
Map<Integer, Person> idToPerson = people.collect(
Collectors.toMap(Person::getId, Function.identity()));Stream<Locale> locales = Stream.of(Locale.getAvailableLocales());
Map<String, String> languageNames = locales.collect(
Collectors.toMap(Locale::getCountry,
Locale::getDisplayLanguage,
(existingValue, newValue) -> existingValue));Map<String, List<Locale>> countryToLocales = locales.collect(
Collectors.groupingBy(Locale::getCountry));List<Locale> swissLocales = countryToLocales.get("CH");
// Yields list of locales [it_CH, de_CH, fr_CH, ...]partitioningBy when the classifier function has a boolean result:
Map<Boolean, List<Locale>> englishAndOtherLocales = locales.collect(
Collectors.partitioningBy(l -> l.getLanguage().equals("en")));
List<Locale>> englishLocales = englishAndOtherLocales.get(true);Stream<Locale> locales() { return Stream.of(Locale.getAvailableLocales()); }
locales().collect(Collectors.toMap(Locale::toString, Locale::getDisplayLanguage))
locales().collect(Collectors.toMap(Locale::getCountry, Locale::getDisplayLanguage))
// Exception—duplicate keys
Map<String, List<Locale>> countryToLocales = locales().collect(
Collectors.groupingBy(Locale::getCountry));
countryToLocales.get("CH")
// See http://archive.ethnologue.com/15/show_language.asp?code=gsw
groupingBy produces a list for each key.Map<String, Set<Locale>> countryToLocaleSet = locales.collect(
groupingBy(Locale::getCountry, toSet()));java.util.stream.Collectors.* to make the expressions easier to read.Map<String, Long> countryToLocaleCounts = locales.collect(
groupingBy(Locale::getCountry, counting()));Map<String, Integer> stateToCityPopulation = cities.collect(
groupingBy(City::getState, summingInt(City::getPopulation)));Map<String, Set<String>> countryToLanguages = locales.collect(
groupingBy(Locale::getDisplayCountry,
mapping(Locale::getDisplayLanguage, toSet())));
filtering, flatMapping:
Map<String, Set<City>> largeCitiesByState
= cities.collect(
groupingBy(City::getState,
filtering(c -> c.getPopulation() > 500000,
toSet())));
cities.filter(...).collect(...)? toUnmodifiableList, toUnmodifiableSet, toUnmodifiableMapreduce is a general mechanism for computing a value from a stream.List<Integer> values = ...; Optional<Integer> sum = values.stream().reduce((x, y) -> x + y);
List<Integer> values = ...;
Integer sum = values.stream().reduce(0, (x, y) -> x + y)
// Computes 0 + v0 + v1 + ...
Optional.reduce for more complex operations.(Int, String) -> Int.int result = words.reduce(0,
(total, word) -> total + word.length(),
(total1, total2) -> total1 + total2);map(String::length) and compute the sum.Stream<T>, where T is a class (or interface).Stream<Integer>, Stream<Double>, etc. are inefficient.IntStream, LongStream, DoubleStream instead.OptionalInt, OptionalLong, OptionalDouble
get, call getAsInt, getAsLong, and getAsDouble
IntStream stream = IntStream.of(1, 1, 2, 3, 5); stream = Arrays.stream(values, from, to);
IntStream and LongStream ranges:
IntStream zeroToNinetyNine = IntStream.range(0, 100); LongStream zeroToTenBillion = LongStream.rangeClosed(0, 10_000_000_000L);
Random.ints, Random.longs, Random.doublesString sentence = "\uD835\uDD46 is the set of octonions.";
IntStream codes = sentence.codePoints();
// A stream with elements 0x1D546 0x20 0x69 0x73 0x20 . . .mapToInt, mapToLong, mapToDouble:
IntStream lengths = words.mapToInt(String::length);
toArray method returns int[], long[], double[]OptionalInt etc.sum, average, max, minsummaryStatistics yields IntSummaryStatistics etc. which simultaneously provide all four results.boxed yields an object stream:
Stream<Integer> integers = IntStream.range(0, 100).boxed();
IntStream.range(0, 10).map(n -> n * n).forEach(System.out::println) new Random().ints().limit(1000).toArray() String hello = "Hello \uD83D\uDE3B"; Arrays.toString(hello.codePoints().toArray()) new Random().ints().map(n -> n % 100).limit(1000).max() new Random().ints().map(n -> n % 100).limit(1000).summaryStatistics()
Stream<String> parallelWords = words.parallelStream(); Stream<String> parallelWords = Stream.of(wordArray).parallel();
int[] shortWords = new int[12];
words.parallelStream().forEach(
s -> { if (s.length() < 12) shortWords[s.length()]++; });
// Error—race condition!
System.out.println(Arrays.toString(shortWords));Map<Integer, Long> shortWordCounts =
words.parallelStream()
.filter(s -> s.length() < 12)
.collect(groupingBy(String::length, counting()));Stream.sorted are ordered.stream.map(fun) can be done in segments that are reassembled in order.distinct, limit) benefit from dropping ordering:
Stream<String> sample = words.parallelStream().unordered().distinct().limit(n);
Collectors.groupingByConcurrent
Map<Integer, List<String>> result = words.parallelStream().collect(
Collectors.groupingByConcurrent(String::length));
// Values aren’t collected in stream order
Files.lines now uses a memory mapped file.Files.lines(pathOfHugeFile)
.parallel()
.filter(l -> l.contains("Exception"))
...