一、何为函数式编程?
函数式编程(Functional Programming,简称FP)是一种编程范式,它将计算视为数学函数的求值,并避免使用可变状态和可变数据。Java函数式编程基于Lambda表达式,在Java中,核心思想是将函数作为一等公民:
- 函数是一等公民:函数可以作为参数传递、作为返回值、赋值给变量。
- 不可变性:避免修改状态,强调使用不可变对象
- 声明式编程:关注"做什么"而不是"如何做"
- 无副作用:函数执行不影响外部状态
二、Lambda表达式
Lambda表达式是java8引入的一种简洁的语法形式,用于表示匿名函数。核心思想是将代码块作为方法参数传递,从而简化代码并提高可读性。 它可以作为参数传递给方法或函数接口,并且可以在需要函数式编程特性的地方使用。Lambda表达式仅适用于函数式接口(只有一个抽象方法的接口),可直接实现该接口的实例,避免编写传统匿名内部类。Lambda表达式是一种匿名函数,可以用来表示一个函数式接口的实现。
基本语法格式:(参数列表)->表达式或代码块
- 参数列表: 可以显示或隐式指定参数类型,只有一个参数时还可以省略括号。
- 箭头符号:->,表示参数和函数体之间的分隔符
- 函数体: 可以是一个表达式或代码块 具体形式如下:
java
// 标准格式
(参数列表) -> { 表达式体 }
// 简化格式
(参数列表) -> 表达式
// 无参数
() -> { 表达式体 }
// 单参数可省略括号
参数 -> 表达式用法示例:
java
// 1. 无参数
() -> System.out.println("Hello");
// 2. 一个参数
(x) -> x * 2;
x -> x * 2; // 单个参数时可省略括号
// 3. 多个参数
(int x, int y) -> x + y; //参数类型显示指定
(x, y) -> x + y; // 参数类型可隐式推断
// 4. 多行代码
(x, y) -> {
int sum = x + y;
return sum * 2;
};使用限制:
- 单方法接口:Lambda表达式只能用于实现一个抽象方法的接口。
- 捕获变量:只能捕获有效最终变量。
- 可读性:如果逻辑复杂,可能会降低代码可读性。
实际开发中的应用:
- stream api
- 事件处理
- 函数式接口
三、函数式接口
函数式接口是只有一个抽象方法的接口,可以使用@FunctionalInterface注解标记。
1.内置函数式接口
- 1.Predicate< T > - 断言接口(接收T返回boolean)
java
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
// 示例
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // true
// 组合使用
Predicate<Integer> isPositive = n -> n > 0;
Predicate<Integer> isPositiveAndEven = isPositive.and(isEven);
// 集合过滤
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evens = numbers.stream()
.filter(isEven)
.collect(Collectors.toList());- 2.Supplier< T > - 供应者接口(无参数返回T)
java
@FunctionalInterface
public interface Supplier< T > {
T get();
}
// 示例
Supplier<Double> randomSupplier = () -> Math.random();
Supplier<String> nameSupplier = () -> "Default";
// 延迟初始化
Supplier<ExpensiveObject> lazyInit = () -> {
System.out.println("Creating expensive object...");
return new ExpensiveObject();
};
// 需要时才创建
ExpensiveObject obj = lazyInit.get();- 3.Consumer< T > - 消费者接口(接收T无返回值)
java
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
// 示例
Consumer<String> printer = s -> System.out.println(s);
Consumer<String> logger = s -> log(s);
// andThen组合
Consumer<String> printAndLog = printer.andThen(logger);
printAndLog.accept("Hello");- 4. Function< T, R > - 函数接口(接收T返回R)
java
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
// 示例
Function<String, Integer> lengthFunc = s -> s.length();
Function<Integer, String> toStringFunc = i -> String.valueOf(i);
// compose和andThen组合
Function<String, String> functionChain = lengthFunc.andThen(toStringFunc);
// 映射示例
List<String> names = Arrays.asList("Tom", "Jerry");
List<Integer> lengths = names.stream()
.map(lengthFunc)
.collect(Collectors.toList());- 5.其他常用函数式接口
java
// UnaryOperator< T > - 一元操作符(Function的特例) 接收T返回T(Function的特殊情况)
UnaryOperator<Integer> square = x -> x * x;
// BinaryOperator<T> - 二元操作符 接收两个T返回T
BinaryOperator<Integer> add = (a, b) -> a + b;
// BiFunction<T, U, R> - 二元函数
BiFunction<Integer, Integer, String> adder = (a, b) -> String.valueOf(a + b);
// BiPredicate<T, U> - 二元断言
BiPredicate<String, Integer> lengthCheck = (s, len) -> s.length() > len;
// BiConsumer<T, U> - 二元消费者
BiConsumer<String, Integer> printer = (name, age) ->
System.out.println(name + ": " + age);2.自定义函数式接口
java
@FunctionalInterface
interface StringProcessor {
String process(String input);
// 可以有默认方法
default StringProcessor andThen(StringProcessor after) {
return input -> after.process(this.process(input));
}
// 可以有静态方法
static StringProcessor toUpperCase() {
return String::toUpperCase;
}
}
// 使用
StringProcessor trimmer = s -> s.trim();
StringProcessor upperCaser = StringProcessor.toUpperCase();
StringProcessor pipeline = trimmer.andThen(upperCaser);
System.out.println(pipeline.process(" hello ")); // HELLO四、Lambda表达式与函数式接口的关系
Lambda表达式是Java实现函数式编程的基础,它提供了简洁的函数定义语法,使得函数可以作为参数传递,从而支持高阶函数等函数式编程特性。Lambda表达式必须与函数式接口结合使用,函数式接口是一个只包含一个抽象方法的接口,用@FunctionInterface注解标注。
五、方法引用
方法引用是Lambda的简化写法,有以下四种形式:
1.静态方法引用
- 语法:
类名::静态方法 - 示例:
java
// Lambda形式
Function<Integer, String> converter1 = i -> String.valueOf(i);
// 方法引用形式
Function<Integer, String> converter2 = String::valueOf;2.任意对象实例方法引用
- 语法:
- 类名::实例方法
- 示例:
java
// Lambda形式
Consumer<String> printer1 = s -> System.out.println(s);
// 方法引用形式
Consumer<String> printer2 = System.out::println;
// 集合排序示例
List<String> names = Arrays.asList("Alice", "Bob");
names.sort(String::compareToIgnoreCase);3.特定对象的实例方法引用
- 语法:
对象::实例方法 - 示例:
java
String prefix = "Mr. ";
Function<String, String> adder = s -> prefix + s;
// 等价于
Function<String, String> adder = prefix::concat;4.构造方法引用
- 语法:
类名::new - 示例:
java
// Lambda形式
Supplier<List<String>> supplier1 = () -> new ArrayList<>();
// 方法引用形式
Supplier<List<String>> supplier2 = ArrayList::new;
// 带参数的构造方法
Function<Integer, int[]> arrayCreator = int[]::new;
int[] arr = arrayCreator.apply(10); // 创建长度为10的数组