Featured resource
2025 Tech Upskilling Playbook
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Check it out
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

Guided: Java SE Functional Interfaces and Lambda Expressions

Practice applying Java SE's built-in functional interfaces and lambda expressions to write concise, modern code. In this Guided Code Lab, you'll simplify tasks such as filtering, transforming, and processing collections using functional programming techniques.

Lab platform
Lab Info
Level
Beginner
Last updated
Feb 13, 2026
Duration
45m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use, and consent to receive marketing emails from Pluralsight.
Table of Contents
  1. Challenge

    Introduction

    Welcome to this Guided Code Lab on Java Functional Interfaces and Lambda Expressions!

    In this lab, you will take a standard Java application that manages a product inventory and refactor it step-by-step to use modern, functional programming techniques. This refactoring improves code clarity and maintainability.

    You will work in the ProductInventory.java file and implement methods that filter, transform, and process a list of products using functional interfaces and lambda expressions.

    It's time to get started! info> This lab experience was developed by the Pluralsight team using Forge, an internally developed AI tool utilizing Gemini technology. All sections were verified by human experts for accuracy prior to publication. For issue reporting, please contact us.

  2. Challenge

    Filtering Collections with Predicate

    Filtering Collections with Predicate

    One of the most common operations on a collection is filtering, or selecting a subset of elements that meet certain criteria.

    The java.util.function.Predicate<T> functional interface is designed for exactly this. It has a single abstract method, boolean test(T t), which returns true if the input argument matches the predicate, and false otherwise.

    Before lambda expressions were introduced, developers implemented this logic by using anonymous inner classes.

    First, you will implement using an anonymous inner class to see how it used to work. Then, you will refactor the code to use a lambda expression and apply it with modern Java APIs such as List.removeIf. ### Removing Elements with removeIf

    The List interface includes default methods that accept functional interfaces. One of these methods is removeIf, which removes all elements that match a given Predicate.

  3. Challenge

    Transforming Data with Function

    Transforming Data with Function

    Another common task you perform in Java is transforming data from one form to another, such as extracting a specific field from an object. The java.util.function.Function<T, R> interface is designed for this purpose. Its R apply(T t) method takes a value of type T and returns a value of type R.

    In this step, you will first implement a data transformation with an anonymous class. Then, you will refactor the code to use a lambda expression and simplify it further with a method reference, which is a shorthand syntax for lambdas that call a single method. You use a Function to transform an input of one type into an output of another. Here, you transform Product objects into String names using an anonymous class first.

  4. Challenge

    Consuming and Supplying Data

    Using Consumer and Supplier

    In this step, you work with two additional core functional interfaces: Consumer and Supplier.

    The java.util.function.Consumer<T> interface represents an operation that accepts a single input argument and returns no result. It defines the void accept(T t) method. You use a Consumer when you need to perform an action on an element, like printing it, saving it to a database, or modifying one of its properties.

    The java.util.function.Supplier<T> interface represents a supplier of results. It defines the T get()method, which takes no arguments and returns a value. You can use a Supplier for lazy initialization or generating default values.

    In the following tasks, you will use a Consumer to apply a discount to products and a Supplier to create a default product instance. A Consumer performs an action on an input but doesn't return anything. It's perfect for tasks like printing, logging, or modifying an object.

    The List.forEach method accepts a Consumer. A Supplier takes no arguments but produces a value. It's useful for lazy generation of objects. Here, you create a Supplier that provides a default Product.

  5. Challenge

    Chaining Operations with Streams

    Building Stream Pipelines with the Stream API

    The true power of functional programming in Java is realized when you start chaining these operations together using the Stream API.

    A stream is a sequence of elements that supports sequential and parallel aggregate operations.

    A stream pipeline consists of:

    • A source, such as a Collection
    • Zero or more intermediate operations, such as filter() or map(), which are lazy and return a new stream
    • A terminal operation, such as collect() or forEach(), which triggers the computation and produces a result or side-effect

    In this step, you will build your first stream pipeline to see how these concepts connect.

  6. Challenge

    Advanced Operations with Maps

    Using Functional Interfaces with Map

    Functional programming isn't just for lists. The Map interface has also been enhanced with powerful methods that leverage functional interfaces.

    In this step, you will explore two of them:

    • computeIfAbsent(K key, Function<K, V> mappingFunction): If the specified key is not already associated with a value, this method attempts to compute its value using the given mapping function and enters it into the map. This is useful for grouping elements from a list into a map.

    • forEach(BiConsumer<K, V> action): This method performs the given action for each entry in the map. A BiConsumer is just like a Consumer but takes two arguments (in this case, the key and the value). The Map interface also gained powerful functional methods.

    You use computeIfAbsent to create and store values in a map only when a key is missing. The method checks whether the specified key is already associated with a value. If it is not, the map calls the provided Function to compute the value, stores it, and returns the result. Finally, process the entries in your newly created map.

    Use Map.forEach to process each key-value pair in a map. The method accepts a BiConsumer, which takes two arguments representing the key and the value, and applies an action to each entry in the map. ### How to Run

    To compile and run the application run the following command in the Terminal:

    mvn compile exec:java -Dexec.mainClass="com.pluralsight.codelab.Main"
    
  7. Challenge

    Conclusion

    Congratulations on completing the lab!

    You have successfully transformed a traditional Java application into a modern, functional programming showcase.

    Throughout this lab, you've learned how to:

    • Use Predicate interfaces with lambda expressions to filter collections
    • Transform data using Function interfaces and method references
    • Process elements with Consumer and generate values with Supplier
    • Chain operations together using the Stream API
    • Leverage functional methods on Map interfaces for grouping and processing

    By applying these functional programming concepts, you can write code that is more concise, readable, and expressive. These patterns are central to modern Java development and will support you in creating cleaner, more maintainable solutions as you continue building your skills.

About the author

Pluralsight Code Labs offer an opportunity to get hands-on learning in real-time. Be it a Challenge, Sandbox, or Guided Lab, these provide the real world experience needed to succeed in your development role.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight