likes
comments
collection
share

Java 8函数式编程特性:掌握Lambda表达式和Stream API的最佳实践

作者站长头像
站长
· 阅读数 76

JDK8最常用的特性可能是Lambda表达式和Stream API。

Lambda表达式允许开发者以更简洁的方式编写匿名函数,从而简化了代码量和提高了可读性。

Stream API 则提供了一种流式处理数据的方式,使得开发者可以更方便地进行集合操作、过滤、映射等操作,并且可以利用多核处理器来提高性能。

这两个特性都对Java 8的函数式编程支持作出了重要贡献。除此之外,JDK8还引入了一些新的API和语言特性,如default方法、Optional类、新的Date/Time API等。

Lambda表达式最常用的写法是带参数和无参数的表达式,以及带返回值的表达式。以下是一些常见的Lambda表达式写法及示例代码:

带参数的Lambda表达式:

// 一个参数(param) -> System.out.println(param);
// 多个参数(a, b) -> a + b;

示例代码:

// 输出集合中所有元素
List<String> list = Arrays.asList("apple", "banana", "orange");
list.forEach(str -> System.out.println(str));

无参数的Lambda表达式:

() -> System.out.println("Hello, World!");

示例代码:

// 定时输出当前时间
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> System.out.println(LocalDateTime.now()), 0, 1, TimeUnit.SECONDS);

带返回值的Lambda表达式:

(a, b) -> { return a + b; };

示例代码:

// 获取集合中长度大于等于5的元素,并返回它们的数量
List<String> list = Arrays.asList("apple", "banana", "orange", "pear", "grapefruit");
long count = list.stream().filter(str -> str.length() >= 5).count();
System.out.println(count); // 3

总的来说,Lambda表达式是Java 8引入的一个非常强大的特性,可以大幅简化代码量和提高可读性。开发者需要熟悉不同类型的Lambda表达式及其使用场景,以便在实际开发中更好地利用这个特性。

Java 8中,函数接口最常用的写法是通过@FunctionalInterface注解来定义。这个注解可以确保该接口只有一个抽象方法,从而被Lambda表达式和方法引用等语法糖使用。

以下是一些常见的函数接口及其定义方式和示例代码:

Predicate:表示一个带有泛型T参数且返回boolean类型值的谓词(判断条件)函数。

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

// 示例代码
Predicate<Integer> isPositive = num -> num > 0;
System.out.println(isPositive.test(5)); // true
System.out.println(isPositive.test(-5)); // false

Function<T, R>:表示一个带有泛型T参数且返回泛型R值的函数。

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}

// 示例代码
Function<String, Integer> strLength = str -> str.length();
System.out.println(strLength.apply("Hello")); // 5

Consumer:表示一个带有泛型T参数且无返回值的消费者函数。

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

// 示例代码
Consumer<String> printMsg = msg -> System.out.println(msg);
printMsg.accept("Hello, World!"); // Hello, World!

Supplier:表示一个不带参数且返回泛型T值的供应商函数。

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

// 示例代码
Supplier<Integer> randomNumber = () -> (int) (Math.random() * 100);
System.out.println(randomNumber.get()); // 随机输出一个[0, 100)之间的整数

总的来说,函数接口是Java 8中非常重要的一个特性,可以大幅简化代码量和提高可读性。开发者需要掌握不同类型的函数接口及其使用场景,以便在实际开发中更好地利用这个特性。

下面是函数接口在真实实践中的用法,认真思考学习一下:

当你有两个类似的方法,它们都包含一个大部分相同的for循环,但是循环体内部的逻辑不同时,可以使用 Consumer 来提取共性。

下面是一个示例代码,我们假设有两个方法 processListA 和 processListB,它们都需要处理一个列表,其中列表中的每个元素都需要进行一些操作。具体来说,在这个例子中,我们要将列表中的每个元素转换成小写(在 processListA 方法中),或者将其转换成大写(在 processListB 方法中)。我们将共性抽象为一个函数式接口 ListProcessor,并将差异作为一个参数传入:

import java.util.Arrays; import java.util.List; import java.util.function.Consumer;

public class Main { public static void main(String[] args) { List list = Arrays.asList("foo", "bar", "baz");

    processListA(list, str -> System.out.println(str.toLowerCase()));
    processListB(list, str -> System.out.println(str.toUpperCase()));
}

private static void processListA(List<String> list, ListProcessor processor) {
    for (String str : list) {
        processor.accept(str);
    }
}

private static void processListB(List<String> list, ListProcessor processor) {
    for (String str : list) {
        processor.accept(str);
    }
}

interface ListProcessor extends Consumer<String> {}

}

在上面的代码中,我们定义了一个函数式接口 ListProcessor,它继承了 Consumer,这样我们就可以将其作为一个参数传递给 processListA 和 processListB 方法。在调用方法时,我们将具体的转换逻辑通过 lambda 表达式传入。

Stream API可以对集合进行各种操作,包括过滤、映射、排序、去重、统计等。以下是一些处理集合最常用的写法及示例代码:

遍历集合:使用forEach()方法可以遍历集合中的每个元素。

List<String> list = Arrays.asList("apple", "banana", "orange");
list.stream().forEach(str -> System.out.println(str));

过滤集合:使用filter()和collect()方法可以根据指定条件过滤出满足条件的元素。

List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> filteredList = list.stream().filter(str -> str.startsWith("a")).collect(Collectors.toList());

映射集合:使用map()和collect()方法可以将集合中每个元素映射成另一个元素。

List<String> list = Arrays.asList("apple", "banana", "orange");
List<Integer> lengthList = list.stream().map(str -> str.length()).collect(Collectors.toList());

排序集合:使用sorted()和collect()方法可以对集合中的元素进行排序。

List<String> list = Arrays.asList("apple", "banana", "orange");
List<String> sortedList = list.stream().sorted().collect(Collectors.toList());

去重集合:使用distinct()和collect()方法可以去除集合中的重复元素。

List<String> list = Arrays.asList("apple", "banana", "orange", "apple");
List<String> distinctList = list.stream().distinct().collect(Collectors.toList());

统计集合:使用count()、max()、min()等方法可以对集合中的元素进行统计。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
long count = numbers.stream().count(); 
Optional<Integer> max = numbers.stream().max(Integer::compareTo); 
Optional<Integer> min = numbers.stream().min(Integer::compareTo);      

总的来说,Stream API是Java 8中非常重要的一个特性,可以大幅简化代码量和提高可读性。开发者需要熟悉不同类型的中间操作和末端操作及其使用场景,以便在实际开发中更好地利用这个特性。

欢迎关注公众号:程序员的思考与落地

公众号提供大量实践案例,Java入门者不容错过哦,可以交流!!

转载自:https://juejin.cn/post/7221164577559511096
评论
请登录