Fundamentals 16 min read

Master Java 8 Lambdas and Streams: Functional Interfaces, Collectors, and Real‑World Examples

This article explains Java 8's lambda expressions and functional interfaces, demonstrates common Stream operations such as filter, map, flatMap, max/min, count, and reduce, and shows how to use built‑in collectors like toList, partitioningBy, groupingBy, and joining with practical code examples.

macrozheng
macrozheng
macrozheng
Master Java 8 Lambdas and Streams: Functional Interfaces, Collectors, and Real‑World Examples

Introduction

Java 8 introduced lambda expressions and functional programming, allowing behavior to be passed as immutable values processed by functions.

Important Functional Interfaces

What is a functional interface?

A functional interface has a single abstract method and can be used as the type of a lambda expression. It may also contain default and static methods and is marked with

@FunctionalInterface

.

Common built‑in functional interfaces include:

Predicate<T> :

boolean test(T t)

– evaluates a condition.

Consumer<T> :

void accept(T t)

– consumes a value.

Function<T,R> :

R apply(T t)

– transforms a value.

Supplier<T> :

T get()

– supplies a value.

UnaryOperator<T> :

T apply(T t)

– unary operation.

BinaryOperator<T> :

T apply(T t, U u)

– binary operation.

<code>public class Test {
    public static void main(String[] args) {
        Predicate<Integer> predicate = x -> x > 185;
        Student student = new Student("9龙", 23, 175);
        System.out.println("9龙的身高高于185吗?:" + predicate.test(student.getStature()));

        Consumer<String> consumer = System.out::println;
        consumer.accept("命运由我不由天");

        Function<Student, String> function = Student::getName;
        String name = function.apply(student);
        System.out.println(name);

        Supplier<Integer> supplier = () -> Integer.valueOf(BigDecimal.TEN.toString());
        System.out.println(supplier.get());

        UnaryOperator<Boolean> unaryOperator = uglily -> !uglily;
        Boolean apply2 = unaryOperator.apply(true);
        System.out.println(apply2);

        BinaryOperator<Integer> operator = (x, y) -> x * y;
        Integer integer = operator.apply(2, 3);
        System.out.println(integer);

        test(() -> "我是一个演示的函数式接口");
    }

    /**
     * Demonstrates a custom functional interface usage
     * @param worker
     */
    public static void test(Worker worker) {
        String work = worker.work();
        System.out.println(work);
    }

    public interface Worker {
        String work();
    }
}
</code>

Stream Basics

Streams allow lazy evaluation; intermediate operations return another Stream, while terminal operations produce a result.

collect(Collectors.toList())

Converts a Stream into a

List

. Similar methods exist for

Set

and

Map

.

<code>public class TestCase {
    public static void main(String[] args) {
        List<Student> studentList = Stream.of(
                new Student("路飞", 22, 175),
                new Student("红发", 40, 180),
                new Student("白胡子", 50, 185)
        ).collect(Collectors.toList());
        System.out.println(studentList);
    }
}
</code>

filter

Filters elements based on a

Predicate

. The operation is lazy.

<code>public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));

        List<Student> list = students.stream()
                .filter(stu -> stu.getStature() < 180)
                .collect(Collectors.toList());
        System.out.println(list);
    }
}
</code>

map

Transforms each element using a

Function

. The operation is lazy.

<code>public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));

        List<String> names = students.stream()
                .map(student -> student.getName())
                .collect(Collectors.toList());
        System.out.println(names);
    }
}
</code>

flatMap

Merges multiple Streams into a single Stream.

<code>public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));

        List<Student> studentList = Stream.of(students,
                asList(new Student("艾斯", 25, 183), new Student("雷利", 48, 176)))
                .flatMap(students1 -> students1.stream())
                .collect(Collectors.toList());
        System.out.println(studentList);
    }
}
</code>

max and min

Find the maximum or minimum element using a

Comparator

. The result is wrapped in an

Optional

to avoid null pointer exceptions.

<code>public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));

        Optional<Student> max = students.stream()
                .max(Comparator.comparing(stu -> stu.getAge()));
        Optional<Student> min = students.stream()
                .min(Comparator.comparing(stu -> stu.getAge()));
        max.ifPresent(System.out::println);
        min.ifPresent(System.out::println);
    }
}
</code>

count

Counts elements after optional filtering. This is a terminal operation.

<code>public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        students.add(new Student("路飞", 22, 175));
        students.add(new Student("红发", 40, 180));
        students.add(new Student("白胡子", 50, 185));

        long count = students.stream()
                .filter(s1 -> s1.getAge() < 45)
                .count();
        System.out.println("年龄小于45岁的人数是:" + count);
    }
}
</code>

reduce

Aggregates a Stream into a single value using an accumulator function.

<code>public class TestCase {
    public static void main(String[] args) {
        Integer reduce = Stream.of(1, 2, 3, 4)
                .reduce(0, (acc, x) -> acc + x);
        System.out.println(reduce);
    }
}
</code>

Advanced Collectors

toList, toSet, toMap

Collects a Stream into a

List

,

Set

or

Map

. Example shown above with

collect(Collectors.toList())

.

partitioningBy

Divides elements into two groups based on a

Predicate

.

<code>Map<Boolean, List<Student>> listMap = students.stream()
        .collect(Collectors.partitioningBy(student ->
                student.getSpecialities().contains(SpecialityEnum.SING)));
</code>

groupingBy

Groups elements by a classification function, similar to SQL

GROUP BY

.

<code>Map<SpecialityEnum, List<Student>> listMap = students.stream()
        .collect(Collectors.groupingBy(student ->
                student.getSpecialities().get(0)));
</code>

joining

Concatenates strings from a Stream. The method can take a delimiter, prefix, and suffix.

<code>String names = students.stream()
        .map(Student::getName)
        .collect(Collectors.joining(",", "[", "]"));
System.out.println(names);
</code>

These collectors enable powerful data transformations when combined with Stream pipelines.

Conclusion

Java 8’s functional features make code more expressive and concise. By chaining Stream operations and using built‑in collectors, developers can write clear, declarative logic for data processing. Experiment with these APIs to refactor existing code and unlock the full potential of lambda expressions.

JavalambdastreamsJava8functional interfacescollectors
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.