Java 8 Lambda Expressions and Stream API: Functional Interfaces and Common Operations

This article introduces Java 8's lambda expressions and functional interfaces, demonstrates custom functional interfaces, and explains how to use the Stream API with lazy and eager evaluation for operations such as collect, filter, map, flatMap, max/min, count, reduce, and various collectors.

Java Captain
Java Captain
Java Captain
Java 8 Lambda Expressions and Stream API: Functional Interfaces and Common Operations

Introduction

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

Important Functional Interfaces in Java

What is a Functional Interface?

A functional interface contains a single abstract method and serves as the target type for lambda expressions. It can be annotated with @FunctionalInterface to let the compiler enforce this rule. Default and static methods are allowed.

Common Java 8 Functional Interfaces

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
     */
    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 example shows lambda usage, method references (e.g., Student::getName), and a custom functional interface.

Lazy and Eager Evaluation

Stream operations are lazy; they return another Stream until a terminal operation triggers eager evaluation to produce a result.

Common Stream Operations

collect(Collectors.toList())

Converts a Stream to a List (also toSet, toMap) and triggers eager evaluation.

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}, ...]

filter

Filters elements using a Predicate (lazy).

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}]

map

Transforms each element using a Function (lazy).

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

flatMap

Merges multiple Streams into one (lazy).

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        // add students ...
        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);
    }
}
//[Student{name='路飞', ...}, Student{name='艾斯', ...}, Student{name='雷利', ...}]

max and min

Finds maximum or minimum values using a Comparator and returns an Optional to avoid null pointers.

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        // add students ...
        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);
    }
}
//Student{name='白胡子', age=50, ...}
//Student{name='路飞', age=22, ...}

count

Counts elements after optional filtering (eager).

public class TestCase {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>(3);
        // add students ...
        long count = students.stream()
            .filter(s1 -> s1.getAge() < 45)
            .count();
        System.out.println("年龄小于45岁的人数是:" + count);
    }
}
//年龄小于45岁的人数是:2

reduce

Reduces a Stream to a single value by repeatedly applying a binary operator.

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

Advanced Collectors

Collecting to Values

Collectors transform a Stream into complex results, such as lists, averages, or custom objects.

public class CollectorsTest {
    public static void main(String[] args) {
        List<Student> students1 = new ArrayList<>(3);
        // add students ...
        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 biggest = biggestGroup(classStream);
        System.out.println("人数最多的班级是:" + biggest.getName());
        System.out.println("一班平均年龄是:" + averageNumberOfStudent(students1));
    }
    private static OutstandingClass biggestGroup(Stream<OutstandingClass> classes) {
        return classes.collect(maxBy(comparing(oc -> oc.getStudents().size())))
            .orElseGet(OutstandingClass::new);
    }
    private static double averageNumberOfStudent(List<Student> students) {
        return students.stream().collect(averagingInt(Student::getAge));
    }
}
//人数最多的班级是:一班
//一班平均年龄是:37.666666666666664

partitioningBy

Splits a Stream into two groups based on a Predicate.

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

groupingBy

Groups elements by a classification function, similar to SQL's GROUP BY.

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

joining

Concatenates strings from a Stream with optional delimiter, prefix, and suffix.

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

Conclusion

The article demonstrates how Java 8 lambda expressions and the Stream API simplify collection processing, making code more expressive and concise. By combining various intermediate and terminal operations, developers can efficiently handle filtering, transformation, aggregation, and grouping tasks.

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 APIJava 8Functional Interfaces
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.