Java 8函数式编程特性:掌握Lambda表达式和Stream API的最佳实践
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