Java8 Lambda表达式与函数式接口
一、Lambda表达式概述
1 什么是Lambda表达式?
定义:Lambda表达式是Java 8引入的一种匿名函数,可以理解为简化的匿名内部类,它允许开发者在不创建具体类的情况下编写短小的功能代码块。
语法:Lambda表达式的基本语法如下:
(parameters) > expression 或 (parameters) > { statements; }
parameters
是参数列表,expression
是一个表达式,statements
是一段语句块,如果只有一个参数,可以省略括号。
// 无参数,无返回值 () > System.out.println("Hello, World!"); // 一个参数,有返回值 (String s) > s.length(); // 多个参数,有返回值 (int a, int b) > a + b;
2 Lambda表达式的语法要点
参数列表:可以有一个或多个参数,若只有一个参数,可以省略括号。
箭头符号:>
用于将参数与Lambda主体分开。
主体:可以是单一表达式或一个代码块,如果是单一表达式,返回值会自动推断;如果是代码块,必须显式地使用return
来返回结果。
3 Lambda表达式的应用场景
集合操作:如filter
、map
、reduce
等操作。
事件处理:如按钮点击等事件的回调处理。
线程执行:简化Runnable
或Callable
的创建。
二、函数式接口
1 函数式接口的定义
定义:函数式接口是Java中仅包含一个抽象方法的接口,它们通常用来作为Lambda表达式的目标类型,Java 8引入了@FunctionalInterface
注解,用来标识函数式接口,这个注解是可选的,但如果加上,会强制编译器检查该接口是否符合函数式接口的定义(只有一个抽象方法)。
示例:
@FunctionalInterface public interface MyFunction { int apply(int x, int y); }
2 Java内置函数式接口
Java 8提供了几个常见的函数式接口,主要位于java.util.function
包中,这些接口广泛应用于Java的集合操作和流式API中。
接口名称 | 方法签名 | 说明 |
Function |
R apply(T t) |
接受一个参数并返回一个结果 |
Predicate |
boolean test(T t) |
接受一个参数并返回一个布尔值 |
Consumer |
void accept(T t) |
接受一个参数但不返回结果 |
Supplier |
T get() |
无参数,返回一个结果 |
UnaryOperator |
T apply(T t) |
一元操作符,接受一个参数并返回同类型结果 |
BinaryOperator |
T apply(T t1, T t2) |
二元操作符,接受两个参数并返回同类型结果 |
BiFunction |
R apply(T t, U u) |
接受两个参数并返回一个结果 |
示例:使用Function
和Predicate
接口
Function<Integer, Integer> square = x > x * x; System.out.println(square.apply(5)); // 输出 25 Predicate<String> isEmpty = s > s.isEmpty(); System.out.println(isEmpty.test("")); // 输出 true
3 自定义函数式接口
除了Java内置的函数式接口外,开发者也可以根据需求定义自己的函数式接口,任何接口只要满足只有一个抽象方法的要求,就可以用作Lambda表达式的目标类型。
@FunctionalInterface public interface MyCalculator { int calculate(int a, int b); }
使用自定义函数式接口:
MyCalculator addition = (a, b) > a + b; System.out.println(addition.calculate(10, 20)); // 输出 30
2.4 函数式接口与面向对象编程(OOF)
通过函数式接口,Java将传统的面向对象编程与函数式编程有机结合,这一切都依赖于接口的抽象和Lambda表达式的简化表示,函数式接口为函数式编程的灵活性提供了坚实的基础,使Java既保留了面向对象的模块化设计,又具备了函数式编程的简洁性和高效性。
三、方法引用
1 什么是方法引用?
定义:方法引用是Java 8引入的另一种简化Lambda表达式的语法形式,它允许开发者直接引用已有的方法,而不必通过Lambda表达式显式地实现,这提高了代码的可读性和复用性。
基本形式:
对象的实例方法引用:instance::method
类的静态方法引用:ClassName::staticMethod
类的实例方法引用:ClassName::method
2 方法引用的种类
类型 | 语法形式 | 示例 |
静态方法引用 | ClassName::staticMethod |
Math::max |
对象实例方法引用 | instance::method |
System.out::println |
类实例方法引用(对于特定对象) | ClassName::method |
String::length |
构造方法引用 | ClassName::new |
ArrayList::new |
3 示例:使用方法引用
List<String> names = Arrays.asList("Alice", "Bob", "Charlie"); names.forEach(System.out::println); // 使用对象的实例方法引用
四、综合案例:Lambda表达式与函数式接口的结合
1 需求描述
假设有一组商品数据,我们需要对这些商品进行过滤、排序和统计,具体需求如下:
1、过滤出价格大于100的商品。
2、根据价格对商品进行降序排序。
3、计算总价格。
2 实现步骤及代码示例
import java.util.*; import java.util.function.*; import java.util.stream.*; class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } } public class Main { public static void main(String[] args) { List<Product> products = Arrays.asList( new Product("Laptop", 999.99), new Product("Smartphone", 499.99), new Product("Tablet", 199.99), new Product("Monitor", 299.99) ); // 过滤出价格大于100的商品 List<Product> filteredProducts = products.stream() .filter(p > p.getPrice() > 100) .collect(Collectors.toList()); // 根据价格对商品进行降序排序 List<Product> sortedProducts = products.stream() .sorted((p1, p2) > Double.compare(p2.getPrice(), p1.getPrice())) .collect(Collectors.toList()); // 计算总价格 double totalPrice = products.stream() .mapToDouble(Product::getPrice) .sum(); System.out.println("Filtered Products: " + filteredProducts); System.out.println("Sorted Products: " + sortedProducts); System.out.println("Total Price: " + totalPrice); } }
3 运行结果分析
Filtered Products:只显示价格大于100的商品。
Sorted Products:按价格降序排列的商品列表。
Total Price:所有商品的总价格。
五、相关问题与解答栏目
问题1:Lambda表达式与匿名内部类有什么区别?
回答:Lambda表达式和匿名内部类都可以实现函数式接口,但Lambda表达式更简洁,匿名内部类需要实现整个接口,而Lambda表达式只需要提供方法体,Lambda表达式可以更好地支持并行流操作,因为它们没有捕获外部类的this
引用。
问题2:为什么函数式接口只能有一个抽象方法?
回答:函数式接口只能有一个抽象方法是因为它的设计初衷是为了简化接口的实现,通过限制只有一个抽象方法,可以避免接口被滥用,确保每个函数式接口都有明确的目的,这也使得编译器能够更好地优化Lambda表达式的使用。
小伙伴们,上文介绍了“Java8简单了解Lambda表达式与函数式接口”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。