O'Reilly logo
live online training icon Live Online training

Refactoring to Java Streams and Lambdas

Topic: Software Development
Heinz Kabutz

Java celebrated its 25th birthday in 2020. Code written in 1995 still runs today, without even having to recompile it. This is one of the biggest reasons why Java has had such success in enterprises.

Over the years, we have seen lots of improvements to make Java code easier to work with. Inner classes came in Java 1.1. A proper collection framework joined us in Java 1.2. Java 5 gave us better type safety with generics.

But the biggest improvement for Java programmers came in Java 8 with Streams and Lambdas. We can now write Java code in the declarative style, rather than imperative. This expresses better the "what", rather than the "how" of the program logic.

Since Java 8, we have had a constant stream of improvements to the Java Programming Language. Records, sealed classes, pattern matching, local variable type inference, and many more. They all serve to make it easier to craft great Java code.

Unfortunately a lot of Java code bases are still stuck in the dark ages of Java 6. This needs refactoring.

In this two-day course we learn how and when to "refactor", focusing on the biggest improvement: Java Streams. However, we also show what else is new in the Java Programming Language.

This is a very hands-on course. Each section has exercises where we get to refactor an existing code base of a large ERP system with 330k LOC.

What you'll learn-and how you can apply it

  • How to refactor to streams and lambdas with and without IDE assistance
  • The place of streams and lambdas in the history of the JDK
  • What is a functional interface?
  • The four core functional interface types found in the java.util.function package
  • How the lambda notation is a shorthand for an anonymous inner class based on a functional interface
  • The long and short forms that lambdas can take depending on their complexity
  • Method references as a further simplification of certain forms of lambda
  • How default and static methods in interfaces can use lambdas to improve generality, correctness and readability
  • When it might be unsafe to use methods like Map.computeIfAbsent
  • The concept of a stream and its relationship to iterable collections
  • Why coding with streams follows the algorithm logic more naturally than using for/while loops
  • How to create, transform and terminate streams using filters, mappings, matchers, collectors, reducers, etc
  • Why we should use collectors rather than forEach to build collections from a stream
  • Using the Optional class to avoid null checks, and how optionals are used with streams
  • How to handle exceptions in lambdas using sneaky throws (without Lombok)
  • How functional interfaces, streams and optionals are optimized for the primitive types int, long and double

This training course is for you because...

  • Intermediate Java programmers wanting to learn how to change traditional Java code into Java Streams and Lambdas

Prerequisites

  • Should be very comfortable with at least Java 6 code.

Course Set-up

Please install the following before the class begins:

  • JDK 11 or later
  • IntelliJ 2020.2 or later
  • Git

Further set-up instructions will be provided at the start of the class.

Recommended Preparation

  • Live Online Training: “Data Structures in Java” by Dr Heinz M. Kabutz on the O'Reilly Learning Platform
  • Read some of Dr Heinz M. Kabutz’s newsletters: https://www.javaspecialists.eu/archive

Recommended Follow-up

  • Live Online Training: “Design Patterns in Java: Deep Dive” by Dr Heinz M. Kabutz on the O'Reilly Learning Platform
  • Sign up to The Java Specialists’ Newsletter for lots of tips on the latest Java developments: https://www.javaspecialists.eu/archive

About your instructor

  • Heinz Kabutz is the author of “The Java Specialists’ Newsletter”, a publication enjoyed by tens of thousands of Java experts in over 145 countries. His book “Dynamic Proxies (in German)” was #1 Bestseller on Amazon.de in Fachbücher für Informatik for about five minutes until Amazon fixed their algorithm. Thanks to a supportive mother, he has now sold 5 copies.

    Heinz’s Java Specialists’ newsletter is filled with amusing anecdotes of life on the Island of Crete. He is a popular speaker at all the best Java conferences around the world, and also at some of the worst. He teaches Java courses in classrooms around the world, where his prime objective is to make absolutely sure that none of his students fall asleep. He is not always successful.

Schedule

The timeframes are only estimates and may vary according to how the class is progressing

DAY 1

Segment 1: Welcome (17 minutes)

  • Introduction
  • Refactoring
  • Inspecting Code with IntelliJ IDEA
  • Java Language Changes

Segment 2.1: Interfaces in Java 8 (28 minutes)

  • Default Methods in Interfaces
  • Exercise: Replace with List.sort
  • Static Methods in Interfaces
  • Functional Interfaces

--- 7 minute break ---

Segment 3: Lambdas and Method References (28 minutes)

  • Converting an Anonymous Type to Lambda Syntax
  • Statement vs Expression Lambda
  • Exercise: Replace anonymous type with lambda
  • Method reference patterns
  • Exercise: Replace lambda with method reference

Segment 4.1: Iterating over Collections and Maps (17 minutes)

  • Iterable forEach()
  • Map forEach()
  • Exercise: Replace loop with forEach()
  • removeIf()
  • Exercise: Replace loop with removeIf()

--- 7 minute break ---

Segment 4.2: Iterating over Collections and Maps (17 minutes)

  • Map Compound Methods
  • Exercise: Replace with Compound Map Methods

Segment 5: Introducing Streams (28 minutes)

  • Stream.all/any/noneMatch()
  • Exercise: Replace with all/any/noneMatch

--- 7 minute break ---

Segment 6: Stream transformation and conversion to a Collection (28 minutes)

  • Stream.map() and collect()
  • Exercise: Replace with Map.collect()

Segment 7.1: Specifying the type of collection (17 minutes)

  • Collectors.toCollection()
  • Exercise: Replace with map() and Collectors.toCollection()

--- 7 minute break ---

Segment 7.2: Specifying the type of collection (11 minutes)

  • Further exercises: Replace with map() and Collectors.toCollection()

Segment 8.1: Filtering a Stream (14 minutes)

  • Stream.filter()
  • Exercise: Replace with map(), filter(), collect()

Conclusion to Day 1 (7 minutes)

DAY 2

Segment 8.2: Filtering a Stream (14 minutes)

  • Further exercise: Replace with map(), filter(), collect()

Segment 9.1: Converting a Stream to a Map (28 minutes)

  • Collectors.toMap()
  • Exercise: Replace with stream(), collect(), Collectors.toMap()

--- 7 minute break ---

Segment 9.2: Converting a Stream to a Map (10 minutes)

  • Further exercise: Replace with stream(), collect(), Collectors.toMap()

Segment 10: Stream reduction (28 minutes)

  • Stream.reduce()
  • Exercise: Replace with stream(), map(), reduce()

--- 7 minute break ---

Segment 11: Handling Streams of Streams (35 minutes)

  • Stream.flatMap()
  • Exercise: Replace with flatMap()

Segment 12: Optionals (10 minutes)

  • Optional, findFirst(), findAny()
  • Exercise: Replace with findFirst() or findAny()

--- 7 minute break ---

Segment 12: Optionals (18 minutes)

  • Optional, findFirst(), findAny()
  • Further exercise: Replace with findFirst() or findAny()

Segment 13.1: Grouping stream data into a Map (27 minutes)

  • groupingBy(), mapping()
  • Exercise: Replace with collect(), groupingBy() and mapping()

--- 7 minute break ---

Segment 13.2: Grouping stream data into a Map (9 minutes)

  • Further Exercise: Replace with collect(), groupingBy() and mapping()

Segment 14.1: Checked Exceptions (28 minutes)

  • Handling checked exceptions
  • Exercise: Handling checked exceptions with ThrowingFunction

Segment 15: Conclusion (5 minutes)