Fundamentals 15 min read

Java 8 Lambda Expressions, Functional Interfaces, and Stream API Tutorial

This article introduces Java 8's lambda expressions and functional interfaces, demonstrates their usage with examples, and explains how to leverage the Stream API—including operations like filter, map, flatMap, reduce, collect, and grouping—to process collections efficiently.

Java Captain
Java Captain
Java Captain
Java 8 Lambda Expressions, Functional Interfaces, and Stream API Tutorial

1. Introduction

Java 8's most significant feature is the introduction of lambda expressions, enabling functional programming by passing behavior as immutable values to functions.

2. Important Functional Interfaces in Java

A functional interface is an interface with a single abstract method, used as the type for lambda expressions. It can be annotated with @FunctionalInterface for compile‑time checking.

2.1 Built‑in Functional Interfaces (example)

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 = ugly -> !ugly;
        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
     */
    public static void test(Worker worker) {
        String work = worker.work();
        System.out.println(work);
    }

    public interface Worker {
        String work();
    }
}
//9龙的身高高于185吗?:false
//命运由我不由天
//9龙
//10
//false
//6
//我是一个演示的函数式接口

The above code shows how to use lambda expressions with built‑in functional interfaces and how to define a custom functional interface.

3. Stream API Overview

Streams allow lazy (intermediate) operations that return another Stream, and eager (terminal) operations that produce a result.

3.1 collect(Collectors.toList())

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);
    }
}
//[Student{name='路飞', age=22, stature=175, specialities=null}, 
// Student{name='红发', age=40, stature=180, specialities=null}, 
// Student{name='白胡子', age=50, stature=185, specialities=null}]

3.2 filter

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);
    }
}
//[Student{name='路飞', age=22, stature=175, specialities=null}]

3.3 map

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        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::getName)
                .collect(Collectors.toList());
        System.out.println(names);
    }
}
//[路飞, 红发, 白胡子]

3.4 flatMap

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

        List<Student> studentList = Stream.of(students,
                Arrays.asList(
                        new Student("艾斯", 25, 183),
                        new Student("雷利", 48, 176)))
                .flatMap(students1 -> students1.stream())
                .collect(Collectors.toList());
        System.out.println(studentList);
    }
}
//[Student{name='路飞', age=22, stature=175, specialities=null}, 
// Student{name='红发', age=40, stature=180, specialities=null}, 
// Student{name='白胡子', age=50, stature=185, specialities=null}, 
// Student{name='艾斯', age=25, stature=183, specialities=null}, 
// Student{name='雷利', age=48, stature=176, specialities=null}]

3.5 max and min

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        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()));
        if (max.isPresent()) {
            System.out.println(max.get());
        }
        if (min.isPresent()) {
            System.out.println(min.get());
        }
    }
}
//Student{name='白胡子', age=50, stature=185, specialities=null}
//Student{name='路飞', age=22, stature=175, specialities=null}

3.6 count

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        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);
    }
}
//年龄小于45岁的人数是:2

3.7 reduce

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);
    }
}
//10

4. Advanced Collectors

Collectors provide a flexible way to transform streams into complex results such as lists, maps, averages, partitions, and groupings.

4.1 CollectorsTest (biggest group & average age)

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

        OutstandingClass ostClass1 = new OutstandingClass("一班", students1);

        List<Student> students2 = new ArrayList<>(students1);
        students2.remove(1);
        OutstandingClass ostClass2 = new OutstandingClass("二班", students2);

        Stream<OutstandingClass> classStream = Stream.of(ostClass1, ostClass2);
        OutstandingClass outstandingClass = biggestGroup(classStream);
        System.out.println("人数最多的班级是:" + outstandingClass.getName());
        System.out.println("一班平均年龄是:" + averageNumberOfStudent(students1));
    }

    private static OutstandingClass biggestGroup(Stream<OutstandingClass> outstandingClasses) {
        return outstandingClasses.collect(
                maxBy(comparing(ostClass -> ostClass.getStudents().size())))
                .orElseGet(OutstandingClass::new);
    }

    private static double averageNumberOfStudent(List<Student> students) {
        return students.stream().collect(averagingInt(Student::getAge));
    }
}
//人数最多的班级是:一班
//一班平均年龄是:37.666666666666664

4.2 PartitioningByTest (boolean partition)

public class PartitioningByTest {
    public static void main(String[] args) {
        // assume List<Student> students is initialized
        Map<Boolean, List<Student>> listMap = students.stream().collect(
                Collectors.partitioningBy(student -> student.getSpecialities().contains(SpecialityEnum.SING)));
    }
}

4.3 GroupingByTest (group by enum)

public class GroupingByTest {
    public static void main(String[] args) {
        // assume List<Student> students is initialized
        Map<SpecialityEnum, List<Student>> listMap =
                students.stream().collect(
                        Collectors.groupingBy(student -> student.getSpecialities().get(0)));
    }
}

4.4 JoiningTest (string concatenation)

public class JoiningTest {
    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));

        String names = students.stream()
                .map(Student::getName)
                .collect(Collectors.joining(",", "[", "]"));
        System.out.println(names);
    }
}
//[路飞,红发,白胡子]

5. Conclusion

The article demonstrates how Java 8's lambda expressions and Stream API simplify collection processing, making code more expressive and concise. By combining stream operations, developers can build powerful data pipelines tailored to their business logic.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaLambdaStream APIFunctional InterfacesCollectors
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

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.