Functional Programming in Java: From Lambdas to Stream API

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Functional Programming in Java: From Lambdas to Stream API



Functional programming (FP) is a paradigm in which computations are represented as the evaluation of mathematical functions, avoiding state changes and data mutation. For a long time, Java remained a strictly object-oriented language, but with the release of Java 8 (2014), it took a huge step towards FP by adding lambda expressions, functional interfaces, and the Stream API. Today, these tools are indispensable for writing concise, readable, and thread-safe code.



In this article, we will break down the key concepts of functional programming in Java: from the basics of lambdas to advanced collection processing with the Stream API. The material is aimed at developers who are already familiar with basic Java syntax but want to master modern approaches.



1. Lambda Expressions and Functional Interfaces



A lambda expression is an anonymous function (a method without a name) that can be passed as an argument or stored in a variable. In Java, a lambda implements a functional interface — an interface with exactly one abstract method (SAM — Single Abstract Method).



Syntax:

(parameters) -> { body }


Example: instead of creating an anonymous class for a comparator:

// Old way (Java 7)Comparator<String> comparator = new Comparator<String>() {    @Override    public int compare(String s1, String s2) {        return s1.length() - s2.length();    }};

// New way (Java 8+)Comparator<String> comparatorLambda = (s1, s2) -> s1.length() - s2.length();


Main functional interfaces in Java (package java.util.function):

  • Predicate<T> — checks a condition (method test).
  • Function<T, R> — transforms an object of type T into R (method apply).
  • Consumer<T> — performs an action on an object (method accept).
  • Supplier<T> — supplies an object without input parameters (method get).


Example with Predicate:

Predicate<Integer> isEven = n -> n % 2 == 0;System.out.println(isEven.test(4)); // trueSystem.out.println(isEven.test(5)); // false


Method References are a shorthand notation for a lambda when the body consists of a single method call:

// Lambdalist.forEach(item -> System.out.println(item));// Method Referencelist.forEach(System.out::println);


2. Stream API: Basic Operations



The Stream API is a powerful tool for processing sequences of data (collections, arrays, files) in a declarative style. A Stream does not store data; it only describes a pipeline of operations. Data is not modified — each step creates a new stream.



Creating a Stream:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");Stream<String> stream = names.stream(); // sequentialStream<String> parallelStream = names.parallelStream(); // parallel


Intermediate operations (return a new Stream):

  • filter(Predicate) — selects elements based on a condition.
  • map(Function) — transforms each element.
  • sorted() / sorted(Comparator) — sorting.
  • distinct() — removes duplicates.
  • limit(n) — limits the number of elements.


Terminal operations (finish the stream, return a result):

  • collect(Collectors.toList()) — collects into a collection.
  • forEach(Con

Blogs

Book Recommendations