Java基础(四:Lambda表达式,Stream API,方法引用操作符)

29 阅读5分钟

Lambda表达式

Lambda表达式是Java 8引入的重要特性,它是一种匿名函数,可以让你更简洁地编写代码。

基本语法

(parameters) -> expression
(parameters) -> { statements; }

示例

// 无参数,单条语句
() -> System.out.println("Hello World")

// 单参数,单条语句
x -> x * x

// 多参数,多条语句
(x, y) -> {
    int sum = x + y;
    return sum;
}

Stream API

Stream API是Java 8中处理集合数据的重要工具,它提供了一种声明式的方式来处理数据集合。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

主要特点

  • 函数式编程:支持链式调用和函数式操作
  • 惰性求值:中间操作不会立即执行
  • 并行处理:支持并行流处理大数据集

Stream 流程

image.png

Stream API 的操作流程通常遵循以下模式:

  1. 创建流 - 从数据源创建 Stream
  2. 中间操作 - 对流进行一系列转换操作(可链式调用)
  3. 终端操作 - 产生最终结果(只能有一个终端操作)
List<String> result = list.stream()           // 创建流
    .filter(s -> !s.isEmpty())               // 中间操作
    .map(String::toUpperCase)                // 中间操作
    .sorted()                                // 中间操作
    .collect(Collectors.toList());          // 终端操作

Stream API速查

1. 中间操作(Intermediate Operations)

基础过滤和转换

  • filter(Predicate<T> predicate)
List<String> list = Arrays.asList("apple", "", "banana", "");
List<String> nonEmpty = list.stream()
    .filter(s -> !s.isEmpty())
    .collect(Collectors.toList());
// 结果: ["apple", "banana"]
  • map(Function<T,R> mapper)
List<String> words = Arrays.asList("hello", "world");
List<Integer> lengths = words.stream()
    .map(String::length)
    .collect(Collectors.toList());
// 结果: [5, 5]
  • flatMap(Function<T,Stream<R>> mapper)
List<List<String>> listOfLists = Arrays.asList(
    Arrays.asList("a", "b"),
    Arrays.asList("c", "d")
);
List<String> flattened = listOfLists.stream()
    .flatMap(List::stream)
    .collect(Collectors.toList());
// 结果: ["a", "b", "c", "d"]

去重和排序

  • distinct()
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4);
List<Integer> unique = numbers.stream()
    .distinct()
    .collect(Collectors.toList());
// 结果: [1, 2, 3, 4]
  • sorted()
List<Integer> numbers = Arrays.asList(3, 1, 4, 2);
List<Integer> sorted = numbers.stream()
    .sorted()
    .collect(Collectors.toList());
// 结果: [1, 2, 3, 4]
  • sorted(Comparator<T> comparator)
List<String> words = Arrays.asList("apple", "pie", "cherry");
List<String> sortedByLength = words.stream()
    .sorted(Comparator.comparing(String::length))
    .collect(Collectors.toList());
// 结果: ["pie", "apple", "cherry"]

限制和跳过

  • limit(long maxSize)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> firstThree = numbers.stream()
    .limit(3)
    .collect(Collectors.toList());
// 结果: [1, 2, 3]
  • skip(long n)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> afterSecond = numbers.stream()
    .skip(2)
    .collect(Collectors.toList());
// 结果: [3, 4, 5]

调试和窥视

  • peek(Consumer<T> action)
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<Integer> result = numbers.stream()
    .peek(System.out::println)
    .map(n -> n * 2)
    .collect(Collectors.toList());
// 输出: 1, 2, 3
// 结果: [2, 4, 6]

2. 终端操作(Terminal Operations)

收集和转换

  • collect(Collector<T,A,R> collector)
List<String> words = Arrays.asList("hello", "world");
List<String> collected = words.stream()
    .collect(Collectors.toList());
  • toArray()
List<String> words = Arrays.asList("hello", "world");
Object[] array = words.stream().toArray();
// 结果: ["hello", "world"]
  • toArray(IntFunction<T[]> generator)
List<String> words = Arrays.asList("hello", "world");
String[] array = words.stream().toArray(String[]::new);
// 结果: ["hello", "world"]

遍历操作

  • forEach(Consumer<T> action)
List<String> words = Arrays.asList("hello", "world");
words.stream().forEach(System.out::println);
// 输出: hello, world
  • forEachOrdered(Consumer<T> action)
List<String> words = Arrays.asList("hello", "world");
words.parallelStream().forEachOrdered(System.out::println);
// 保证输出顺序: hello, world

归约操作

  • reduce(BinaryOperator<T> accumulator)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Optional<Integer> sum = numbers.stream()
    .reduce(Integer::sum);
// 结果: Optional[10]
  • reduce(T identity, BinaryOperator<T> accumulator)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Integer sum = numbers.stream()
    .reduce(0, Integer::sum);
// 结果: 10
  • reduce(U identity, BiFunction<U,T,U> accumulator, BinaryOperator<U> combiner)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
Integer sum = numbers.parallelStream()
    .reduce(0, Integer::sum, Integer::sum);
// 结果: 10

查找和匹配

  • findFirst()
List<String> words = Arrays.asList("apple", "banana", "cherry");
Optional<String> first = words.stream()
    .filter(s -> s.startsWith("b"))
    .findFirst();
// 结果: Optional["banana"]
  • findAny()
List<String> words = Arrays.asList("apple", "banana", "cherry");
Optional<String> any = words.parallelStream()
    .filter(s -> s.startsWith("b"))
    .findAny();
// 结果: Optional["banana"] (任意一个)
  • anyMatch(Predicate<T> predicate)
List<String> words = Arrays.asList("apple", "banana", "cherry");
boolean hasLongWord = words.stream()
    .anyMatch(s -> s.length() > 5);
// 结果: true
  • allMatch(Predicate<T> predicate)
List<String> words = Arrays.asList("apple", "banana", "cherry");
boolean allLong = words.stream()
    .allMatch(s -> s.length() > 3);
// 结果: true
  • noneMatch(Predicate<T> predicate)
List<String> words = Arrays.asList("apple", "banana", "cherry");
boolean noEmpty = words.stream()
    .noneMatch(String::isEmpty);
// 结果: true

统计操作

  • count()
List<String> words = Arrays.asList("apple", "banana", "cherry");
long count = words.stream().count();
// 结果: 3
  • min(Comparator<T> comparator)
List<String> words = Arrays.asList("apple", "banana", "cherry");
Optional<String> shortest = words.stream()
    .min(Comparator.comparing(String::length));
// 结果: Optional["apple"]
  • max(Comparator<T> comparator)
List<String> words = Arrays.asList("apple", "banana", "cherry");
Optional<String> longest = words.stream()
    .max(Comparator.comparing(String::length));
// 结果: Optional["banana"] 或 Optional["cherry"]

3. Collectors 收集器

基础收集

  • toList()
List<String> words = Arrays.asList("hello", "world");
List<String> list = words.stream()
    .collect(Collectors.toList());
  • toSet()
List<String> words = Arrays.asList("hello", "world", "hello");
Set<String> set = words.stream()
    .collect(Collectors.toSet());
// 结果: {"hello", "world"}
  • toCollection(Supplier<Collection<T>> collectionFactory)
List<String> words = Arrays.asList("hello", "world");
LinkedList<String> linkedList = words.stream()
    .collect(Collectors.toCollection(LinkedList::new));

字符串连接

  • joining()
List<String> words = Arrays.asList("hello", "world");
String joined = words.stream()
    .collect(Collectors.joining());
// 结果: "helloworld"
  • joining(CharSequence delimiter)
List<String> words = Arrays.asList("hello", "world");
String joined = words.stream()
    .collect(Collectors.joining(", "));
// 结果: "hello, world"
  • joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix)
List<String> words = Arrays.asList("hello", "world");
String joined = words.stream()
    .collect(Collectors.joining(", ", "[", "]"));
// 结果: "[hello, world]"

分组和分区

  • groupingBy(Function<T,K> classifier)
List<String> words = Arrays.asList("apple", "ant", "banana", "cat");
Map<Character, List<String>> grouped = words.stream()
    .collect(Collectors.groupingBy(s -> s.charAt(0)));
// 结果: {'a': ["apple", "ant"], 'b': ["banana"], 'c': ["cat"]}
  • groupingBy(Function<T,K> classifier, Collector<T,A,D> downstream)
List<String> words = Arrays.asList("apple", "ant", "banana", "cat");
Map<Character, Long> countByFirstChar = words.stream()
    .collect(Collectors.groupingBy(
        s -> s.charAt(0),
        Collectors.counting()
    ));
// 结果: {'a': 2, 'b': 1, 'c': 1}
  • partitioningBy(Predicate<T> predicate)
List<String> words = Arrays.asList("apple", "ant", "banana", "cat");
Map<Boolean, List<String>> partitioned = words.stream()
    .collect(Collectors.partitioningBy(s -> s.length() > 3));
// 结果: {true: ["apple", "banana"], false: ["ant", "cat"]}

统计收集

  • summingInt(ToIntFunction<T> mapper)
List<String> words = Arrays.asList("apple", "ant", "banana");
int totalLength = words.stream()
    .collect(Collectors.summingInt(String::length));
// 结果: 13
  • averagingInt(ToIntFunction<T> mapper)
List<String> words = Arrays.asList("apple", "ant", "banana");
double avgLength = words.stream()
    .collect(Collectors.averagingInt(String::length));
// 结果: 4.333...

综合统计

  • summarizingInt(ToIntFunction<T> mapper)
List<String> words = Arrays.asList("apple", "ant", "banana");
IntSummaryStatistics stats = words.stream()
    .collect(Collectors.summarizingInt(String::length));
// 包含: count, sum, min, average, max

映射和转换

  • mapping(Function<T,U> mapper, Collector<U,A,R> downstream)
List<String> words = Arrays.asList("apple", "ant", "banana");
Map<Character, Set<Integer>> result = words.stream()
    .collect(Collectors.groupingBy(
        s -> s.charAt(0),
        Collectors.mapping(
            String::length,
            Collectors.toSet()
        )
    ));
// 结果: {'a': {5, 3}, 'b': {6}}

最值收集

  • maxBy(Comparator<T> comparator)
List<String> words = Arrays.asList("apple", "ant", "banana");
Optional<String> longest = words.stream()
    .collect(Collectors.maxBy(Comparator.comparing(String::length)));
// 结果: Optional["banana"]

4. 并行流操作

  • parallel()
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> doubled = numbers.parallelStream()
    .map(n -> n * 2)
    .collect(Collectors.toList());
  • sequential()
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.parallelStream()
    .sequential()
    .map(n -> n * 2)
    .collect(Collectors.toList());
  • unordered()
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> result = numbers.parallelStream()
    .unordered()
    .distinct()
    .collect(Collectors.toList());

:: 是 Java 8 引入的方法引用操作符(Method Reference Operator)。

主要用途

  • 简化 Lambda 表达式 - 当 Lambda 表达式只是调用一个现有方法时,可以用方法引用来替代

四种方法引用形式

  1. 静态方法引用 - ClassName::staticMethod
List<String> list = Arrays.asList("1", "2", "3");
List<Integer> numbers = list.stream()
    .map(Integer::parseInt)  // 等价于 s -> Integer.parseInt(s)
    .collect(Collectors.toList());
  1. 实例方法引用 - instance::method
List<String> list = Arrays.asList("hello", "world");
list.forEach(System.out::println);  // 等价于 s -> System.out.println(s)
  1. 对象方法引用 - ClassName::method
List<String> list = Arrays.asList("hello", "world");
List<String> upper = list.stream()
    .map(String::toUpperCase)  // 等价于 s -> s.toUpperCase()
    .collect(Collectors.toList());
  1. 构造方法引用 - ClassName::new
List<String> list = Arrays.asList("hello", "world");
Stream<StringBuilder> builders = list.stream()
    .map(StringBuilder::new);  // 等价于 s -> new StringBuilder(s)

方法引用使代码更加简洁易读,是 Stream API 中常用的语法糖。