Functional Programming in Java

(notes from Functional Programming in Java: Harnessing the Power Of Java 8 Lambda Expressions)

Chapter 1: Hello, Lambda Expressions!

enforcing policies

// old style
Transaction transaction = getFromTransactionFactory();
// ...
// with lambda
runWithinTransaction((Transaction transaction) -> {
    // ...

if a method takes a functional interface as a parameter, then we can pass the following:

  • An anonymous inner class (the old way)
  • A lambda expressions
  • A method or constructor reference

Chapter 2: Using Collections

Iterating through a List

very old way:

final List<String> friends = Arrays.asList("Brian", "Nate" ...);
for(int i = 0; i < friends.size(); i++) {

old way:

for(String name : friends) {

using java 8 forEach:

friends.forEach(new Consumer<String>() {
    public void accept(final String name) {

with lambda:

friends.forEach((final String name) -> System.out.println(name));

with type inference:

friends.forEach((name) -> System.out.println(name));

for single parameter, leave off the parentheses:

friends.forEach(name -> System.out.println(name));

with method reference: (final version)


some Stream examples:

// map
    .map(name -> name.length())
    .forEach(count -> System.out.println(count + " "));
// method reference
// filter
final List<String> startsWithN =
        .filter(name -> name.startsWith("N"))

Lexical Scoping

final Function<String, Predicate<String>> startsWithLetter = (String letter) -> (String name) -> name.startsWith(letter);

final long countFriendsStartN =

Pick an element

public static void pickName(
    final List<String> names, final String startingLetter) {
    final Optional<String> foundName =
        .filter(name -> name.startsWith(startingLetter))
    foundName.ifPresent(name -> System.out.println("hello " + name));


final String steveOrLonger =
        .reduce("Steve", (name1, name2) ->
            name1.length() => name2.length() ? name1 : name2);


        .collect(joining(", "));

Chapter 3: Strings, Comparators, and Filters

Iterating a String

    .filter(ch -> Character.isDigit(ch))
    .forEach(ch -> System.out.println((char) ch));

    .sorted((person1, person2) -> person1.getName().compareTo(person2.getName()))

Multiple Compare

final Function<Person, Integer> byAge = person -> person.getAge();
final Function<Person, String> byTheirName = person -> person.getName();


the collect() method needs to know 3 things to gather results into a container:

  1. how to make a result container (ArrayList::new)
  2. how to add a single element (ArrayList::add)
  3. how to merge one result container into another (ArrayList::addAll)
    List<Person> olderThan20 =
            .filter(person -> person.getAge() > 20)
            .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);

use Collectors utility class, just use toList()

// same as above
List<Person> olderThan20 =
        .filter(person -> person.getAge() > 20)

more examples:

Map<Integer, List<Person>> peopleByAge =
Map<Integer, List<String>> nameOfPeopleByAge =
            groupingBy(Person::getAge, mapping(Person::getName, toList())));
Comparator<Person> byAge = Comparator.comparing(Person::getAge);
Map<Character, Optional<Person>> oldestPersonOfEachLetter =
    .collect(groupingBy(person -> person.getName().charAt(0),

List files in a directory

Files.newDirectoryStream(Paths.get("/tmp"), path -> path.toString().endsWith(".java"))
new File(".").listFiles(File::isHidden);

list immediate subdirectories

List<File> files =
    Stream.of(new File(".").listFiles())
        .flatMap(file -> file.listfiles() == null ?
            Stream.of(file) : Stream.of(file.listFiles()))

Watching file change

final Path path = Paths.get(".");
final WatchService watchService = path.getFileSystem().newWatchService();
path.register(watchService, ENTRY_MODIFY);
final WatchKey watchKey = watchService.poll(1, TimeUnit.MINUTES);
if (watchKey != null) {
        .forEach(event -> System.out.println(event.context()));

Chapter 4: Designing with Lambda Expressions

Separating Concerns Using Lambda Expressions
Delegating Using Lambda Expressions
Decorating Using Lambda Expressions
A Peek into the default Methods
Creating Fluent Interfaces Using Lambda Expressions
Dealing with Exceptions

Chapter 5: Working with Resources

Cleaning Up Resources
Using Lambda Expressions to Clean Up Resources
Managing Locks
Creating Concise Exception Tests

Chapter 6: Being Lazy

Delayed Initialization
Lazy Evaluations
Leveraging the Laziness of Streams
Creating Infinite, Lazy Collections

Chapter 7: Optimizing Recursions

Using Tail-Call Optimization
Speeding Up with Memoization

Chapter 8: Composing with Lambda Expressions

Using Function Composition
Using MapReduce
Taking a Leap to Parallelize

Chapter 9: Bringing It All Together

Essential Practices to Succeed with the Functional Style
Performance Concerns
Adopting the Functional Style
Search Blog: