文章目录
前言
当你迷茫的时候,请点击 目录大纲 快速查看前面的技术文章,相信你总能找到前行的方向
另外,本文相关代码已上传 gitee仓库,欢迎关注收藏
函数式编程
函数式编程(Functional Programming,FP)是一种编程范式,它将计算视为数学函数的求值,并避免使用可变状态和可变数据。在Java中,函数式编程主要通过Lambda表达式和方法引用来实现。
Java函数式编程的核心概念
函数式接口(Functional Interface)
定义一个抽象方法的接口,方法的就能以这个接口形式进行传参。
// 只有一个抽象方法的接口
@FunctionalInterface
public interface MyFunction {
int apply(int a, int b);
// 可以有默认方法
default void printResult(int result) {
System.out.println("结果: " + result);
}
// 可以有静态方法
static MyFunction add() {
return (a, b) -> a + b;
}
}
这样,函数可以当成一个普通参数进行传递,例如 MyFunction.add() 直接传参,在 func.apply(a, b) 使用方法参数调用加法。
public static void main(String[] args) {
// 函数式接口
doSomething(MyFunction.add(),2,3);
}
private static void doSomething(MyFunction func,int a,int b){
int res = func.apply(a, b); // 调用add()方法求 a+b
func.printResult(res); // MyFunction printResult 结果: 5
}
Lambda表达式
// 基本语法: (parameters) -> expression
// 或: (parameters) -> { statements; }
// 示例
public static void main(String[] args) {
Runnable runnable = () -> System.out.println("-1- runnable: Hello");
Thread t = new Thread(runnable);
t.start();
Comparator<Integer> comparator = (a, b) -> a - b;
System.out.println("-2- comparator 排序:"+ Stream.of(9,5,6,3,4,2,1,8,7).sorted(comparator).collect(Collectors.toList()));
MyFunction add = (a, b) -> a + b;
MyFunction multiply = (a, b) -> a * b;
System.out.println("-3- add.apply(2,3): " + add.apply(2, 3));
System.out.println("-4- multiply.apply(2,3): " + multiply.apply(2, 3));
}
结果如下:
-1- runnable: Hello
-2- comparator 排序:[1, 2, 3, 4, 5, 6, 7, 8, 9]
-3- add.apply(2,3): 5
-4- multiply.apply(2,3): 6
Java内置的函数式接口
常用函数式接口
private static void testCommFunction() {
// Predicate<T> - 接受一个参数,返回boolean
Predicate<String> isLong = s -> s.length() > 5;
System.out.println(isLong.test("Hello")); // false
// Function<T, R> - 接受一个参数,返回结果
Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Hello")); // 5
// Consumer<T> - 接受一个参数,无返回值
Consumer<String> printer = System.out::println;
printer.accept("Hello World");
// Supplier<T> - 无参数,返回一个结果
Supplier<Double> randomSupplier = Math::random;
System.out.println(randomSupplier.get());
// UnaryOperator<T> - 接受一个参数,返回同类型结果
UnaryOperator<String> toUpper = String::toUpperCase;
System.out.println(toUpper.apply("hello")); // HELLO
// BinaryOperator<T> - 接受两个同类型参数,返回同类型结果
BinaryOperator<Integer> sum = Integer::sum;
System.out.println(sum.apply(5, 3)); // 8
}
方法引用(Method Reference)
private static void testMethodRefFunction() {
List<String> names = Arrays.asList("Charlie", "Alice", "Bob", "\n");
// 1. 静态方法引用
names.forEach(System.out::println);
// 2. 实例方法引用
String prefix = "Hello, ";
names.stream().map(prefix::concat).forEach(System.out::println);
// 3. 特定类型的任意对象方法引用
names.sort(String::compareToIgnoreCase);
// 4. 构造方法引用
names.stream()
.map(String::new)
.forEach(System.out::println);
// 自定义方法用于方法引用
System.out.println("\n过滤偶数:" + Stream.of(9, 5, 6, 3, 4, 2, 1, 8, 7).filter(Main::isEven).collect(Collectors.toList()));
}
public static boolean isEven(int number) {
return number % 2 == 0;
}
结果如下:
Charlie
Alice
Bob
Hello, Charlie
Hello, Alice
Hello, Bob
Hello,
Alice
Bob
Charlie
过滤偶数:[6, 4, 2, 8]
Stream API - 函数式编程的核心工具
Stream基本操作
public static void testStream() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 过滤和映射
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0) // 中间操作:过滤偶数
.map(n -> n * n) // 中间操作:平方
.collect(Collectors.toList()); // 终端操作:收集结果
System.out.println(result); // [4, 16, 36, 64, 100]
// 更多操作
numbers.stream()
.distinct() // 去重
.sorted() // 排序
.limit(5) // 限制数量
.skip(2) // 跳过前n个
.forEach(System.out::println); // 遍历
}
高级Stream操作
public static void testStream2() {
List<String> words = Arrays.asList("Hello", "World", "Java", "Stream");
// 归约操作
Optional<Integer> totalLength = words.stream()
.map(String::length)
.reduce(Integer::sum);
System.out.println("总长度: " + totalLength.orElse(0));
// 分组
Map<Integer, List<String>> lengthMap = words.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println("按长度分组: " + lengthMap);
// 分区
Map<Boolean, List<String>> partition = words.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 4));
System.out.println("按长度分区: " + partition);
// 连接字符串
String joined = words.stream()
.collect(Collectors.joining(", ", "[", "]"));
System.out.println("连接结果: " + joined);
}
结果如下:
总长度: 20
按长度分组: {4=[Java], 5=[Hello, World], 6=[Stream]}
按长度分区: {false=[Java], true=[Hello, World, Stream]}
连接结果: [Hello, World, Java, Stream]
Optional类 - 避免空指针异常
public static void testOptional() {
// 创建Optional
Optional<String> empty = Optional.empty();
Optional<String> nonEmpty = Optional.of("Hello");
Optional<String> nullable = Optional.ofNullable(null);
// 使用Optional
String result = nullable
.map(String::toUpperCase) // 如果值存在则转换
.orElse("Default Value"); // 如果为空返回默认值
System.out.println(result); // Default Value
nullable.ifPresent(value -> System.out.println("值存在: " + value));
// 链式操作
Optional<String> finalResult = Optional.of(nonEmpty
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.orElse("FALLBACK"));
System.out.println(finalResult.get()); // HELLO
}
函数组合和高阶函数
public static void testComposeFunction() {
// 函数组合
Function<Integer, Integer> multiplyBy2 = x -> x * 2;
Function<Integer, Integer> add3 = x -> x + 3;
// andThen: 先执行当前函数,再执行参数函数
Function<Integer, Integer> multiplyAndAdd = multiplyBy2.andThen(add3);
System.out.println(multiplyAndAdd.apply(5)); // 13
// compose: 先执行参数函数,再执行当前函数
Function<Integer, Integer> addAndMultiply = multiplyBy2.compose(add3);
System.out.println(addAndMultiply.apply(5)); // 16
// Predicate组合
Predicate<Integer> isEven = x -> x % 2 == 0;
Predicate<Integer> isGreaterThan10 = x -> x > 10;
Predicate<Integer> isEvenAndGreaterThan10 = isEven.and(isGreaterThan10);
System.out.println(isEvenAndGreaterThan10.test(12)); // true
System.out.println(isEvenAndGreaterThan10.test(8)); // false
// Consumer组合
Consumer<String> print = System.out::println;
Consumer<String> printTwice = print.andThen(print);
printTwice.accept("Hello");
}
实际应用案例
数据处理管道
定义 Person 类
public class Person {
private String name;
private int age;
private double salary;
public Person(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
// getters
public String getName() { return name; }
public int getAge() { return age; }
public double getSalary() { return salary; }
}
测试程序
public static void testPipeline() {
List<Person> people = Arrays.asList(
new Person("Alice", 25, 50000),
new Person("Bob", 30, 60000),
new Person("Charlie", 35, 70000),
new Person("Diana", 28, 55000)
);
// 复杂的数据处理管道
Map<String, Double> result = people.stream()
// 过滤年龄
.filter(p -> p.getAge() > 25)
// 按薪资排序
.sorted(Comparator.comparing(Person::getSalary))
// 分组求平均薪资
.collect(Collectors.groupingBy(
p -> p.getAge() > 30 ? "Senior" : "Junior",
Collectors.averagingDouble(Person::getSalary)
));
System.out.println(result);
}
异步编程
import java.util.concurrent.*;
import java.util.function.*;
public class AsyncProgramming {
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "Hello";
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
});
CompletableFuture<String> result = future
.thenApply(String::toUpperCase)
.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"))
.exceptionally(ex -> "Error: " + ex.getMessage());
System.out.println(result.get()); // HELLO World
}
}
常见陷阱
// 在Lambda中修改外部变量
public static void modifyingExternalVariable() {
int[] counter = {0};
List<String> items = Arrays.asList("A", "B", "C");
// 不好的做法:修改外部变量
items.forEach(item -> counter[0]++);
System.out.println(counter[0]);
// 好的做法:使用归约
long count = items.stream().count();
System.out.println(count);
}
//过度使用链式操作
public static void avoidOverChaining() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 不好的:过度链式操作,难以调试
int result = numbers.stream()
.filter(n -> n > 2)
.map(n -> n * 2)
.sorted()
.distinct()
.reduce(0, Integer::sum);
System.out.println(result);
// 好的:分步骤,清晰可读
List<Integer> filtered = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toList());
List<Integer> doubled = filtered.stream()
.map(n -> n * 2)
.collect(Collectors.toList());
int sum = doubled.stream()
.reduce(0, Integer::sum);
System.out.println(sum);
}
总结
Java函数式编程的核心要点:
- 函数式接口:只有一个抽象方法的接口
- Lambda表达式:简洁的函数表示法
- 方法引用:更简洁的Lambda写法
- Stream API:强大的数据处理工具
- Optional:优雅的空值处理
- 函数组合:构建复杂操作
函数式编程使代码更简洁、可读性更强,并且更容易进行并行处理。但需要注意合理使用,避免过度复杂化。
完整代码
函数式接口 MyFunction.java
package function;
@FunctionalInterface
public interface MyFunction {
int apply(int a, int b);
//可以有默认方法
default void printResult(int result) {
System.out.println("MyFunction printResult 结果: " + result);
}
//可以有静态方法
static MyFunction add() {
return (a, b) -> a + b;
}
}
Person.java
package function;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
class Person {
private String name;
private int age;
private double salary;
}
主测试类 Main.java
package function;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 函数式编程测试
*/
public class Main {
public static void main(String[] args) throws Exception {
// 函数式接口
doSomething(MyFunction.add(), 2, 3);
// Lambda函数接口
testLambdaFunction();
// 常用函数式接口
testCommFunction();
// 方法引用
testMethodRefFunction();
// stream 基本操作
testStream();
// 高级Stream操作
testStream2();
// optional
testOptional();
// 函数组合
testComposeFunction();
// 数据处理管道
testPipeline();
// 异步编程
testAsync();
// 在Lambda中修改外部变量
modifyingExternalVariable();
//过度使用链式操作
avoidOverChaining();
}
private static void testMethodRefFunction() {
List<String> names = Arrays.asList("Charlie", "Alice", "Bob", "\n");
// 1. 静态方法引用
names.forEach(System.out::println);
// 2. 实例方法引用
String prefix = "Hello, ";
names.stream().map(prefix::concat).forEach(System.out::println);
// 3. 特定类型的任意对象方法引用
names.sort(String::compareToIgnoreCase);
// 4. 构造方法引用
names.stream()
.map(String::new)
.forEach(System.out::println);
// 自定义方法用于方法引用
System.out.println("\n过滤偶数:" + Stream.of(9, 5, 6, 3, 4, 2, 1, 8, 7).filter(Main::isEven).collect(Collectors.toList()));
}
public static boolean isEven(int number) {
return number % 2 == 0;
}
private static void doSomething(MyFunction func, int a, int b) {
int res = func.apply(a, b);
func.printResult(res);
}
private static void testLambdaFunction() {
Runnable runnable = () -> System.out.println("-1- runnable: Hello");
Thread t = new Thread(runnable);
t.start();
Comparator<Integer> comparator = (a, b) -> a - b;
System.out.println("-2- comparator 排序:" + Stream.of(9, 5, 6, 3, 4, 2, 1, 8, 7).sorted(comparator).collect(Collectors.toList()));
MyFunction add = (a, b) -> a + b;
MyFunction multiply = (a, b) -> a * b;
System.out.println("-3- add.apply(2,3): " + add.apply(2, 3));
System.out.println("-4- multiply.apply(2,3): " + multiply.apply(2, 3));
}
private static void testCommFunction() {
// Predicate<T> - 接受一个参数,返回boolean
Predicate<String> isLong = s -> s.length() > 5;
System.out.println(isLong.test("Hello")); // false
// Function<T, R> - 接受一个参数,返回结果
Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Hello")); // 5
// Consumer<T> - 接受一个参数,无返回值
Consumer<String> printer = System.out::println;
printer.accept("Hello World");
// Supplier<T> - 无参数,返回一个结果
Supplier<Double> randomSupplier = Math::random;
System.out.println(randomSupplier.get());
// UnaryOperator<T> - 接受一个参数,返回同类型结果
UnaryOperator<String> toUpper = String::toUpperCase;
System.out.println(toUpper.apply("hello")); // HELLO
// BinaryOperator<T> - 接受两个同类型参数,返回同类型结果
BinaryOperator<Integer> sum = Integer::sum;
System.out.println(sum.apply(5, 3)); // 8
}
public static void testStream() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// 过滤和映射
List<Integer> result = numbers.stream()
.filter(n -> n % 2 == 0) // 中间操作:过滤偶数
.map(n -> n * n) // 中间操作:平方
.collect(Collectors.toList()); // 终端操作:收集结果
System.out.println(result); // [4, 16, 36, 64, 100]
// 更多操作
numbers.stream()
.distinct() // 去重
.sorted() // 排序
.limit(5) // 限制数量
.skip(2) // 跳过前n个
.forEach(System.out::println); // 遍历
}
public static void testStream2() {
List<String> words = Arrays.asList("Hello", "World", "Java", "Stream");
// 归约操作
Optional<Integer> totalLength = words.stream()
.map(String::length)
.reduce(Integer::sum);
System.out.println("总长度: " + totalLength.orElse(0));
// 分组
Map<Integer, List<String>> lengthMap = words.stream()
.collect(Collectors.groupingBy(String::length));
System.out.println("按长度分组: " + lengthMap);
// 分区
Map<Boolean, List<String>> partition = words.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 4));
System.out.println("按长度分区: " + partition);
// 连接字符串
String joined = words.stream()
.collect(Collectors.joining(", ", "[", "]"));
System.out.println("连接结果: " + joined);
}
public static void testOptional() {
// 创建Optional
Optional<String> empty = Optional.empty();
Optional<String> nonEmpty = Optional.of("Hello");
Optional<String> nullable = Optional.ofNullable(null);
// 使用Optional
String result = nullable
.map(String::toUpperCase) // 如果值存在则转换
.orElse("Default Value"); // 如果为空返回默认值
System.out.println(result); // Default Value
nullable.ifPresent(value -> System.out.println("值存在: " + value));
// 链式操作
Optional<String> finalResult = Optional.of(nonEmpty
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.orElse("FALLBACK"));
System.out.println(finalResult.get()); // HELLO
}
public static void testComposeFunction() {
// 函数组合
Function<Integer, Integer> multiplyBy2 = x -> x * 2;
Function<Integer, Integer> add3 = x -> x + 3;
// andThen: 先执行当前函数,再执行参数函数
Function<Integer, Integer> multiplyAndAdd = multiplyBy2.andThen(add3);
System.out.println(multiplyAndAdd.apply(5)); // 13
// compose: 先执行参数函数,再执行当前函数
Function<Integer, Integer> addAndMultiply = multiplyBy2.compose(add3);
System.out.println(addAndMultiply.apply(5)); // 16
// Predicate组合
Predicate<Integer> isEven = x -> x % 2 == 0;
Predicate<Integer> isGreaterThan10 = x -> x > 10;
Predicate<Integer> isEvenAndGreaterThan10 = isEven.and(isGreaterThan10);
System.out.println(isEvenAndGreaterThan10.test(12)); // true
System.out.println(isEvenAndGreaterThan10.test(8)); // false
// Consumer组合
Consumer<String> print = System.out::println;
Consumer<String> printTwice = print.andThen(print);
printTwice.accept("Hello");
}
public static void testPipeline() {
List<Person> people = Arrays.asList(
new Person("Alice", 25, 50000),
new Person("Bob", 30, 60000),
new Person("Charlie", 35, 70000),
new Person("Diana", 28, 55000)
);
// 复杂的数据处理管道
Map<String, Double> result = people.stream()
// 过滤年龄
.filter(p -> p.getAge() > 25)
// 按薪资排序
.sorted(Comparator.comparing(Person::getSalary))
// 分组求平均薪资
.collect(Collectors.groupingBy(
p -> p.getAge() > 30 ? "Senior" : "Junior",
Collectors.averagingDouble(Person::getSalary)
));
System.out.println(result);
}
public static void testAsync() throws Exception {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "Hello";
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
});
CompletableFuture<String> result = future
.thenApply(String::toUpperCase)
.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"))
.exceptionally(ex -> "Error: " + ex.getMessage());
// HELLO World
System.out.println(result.get());
}
public static void modifyingExternalVariable() {
int[] counter = {0};
List<String> items = Arrays.asList("A", "B", "C");
// 不好的做法:修改外部变量
items.forEach(item -> counter[0]++);
System.out.println(counter[0]);
// 好的做法:使用归约
long count = items.stream().count();
System.out.println(count);
}
public static void avoidOverChaining() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// 不好的:过度链式操作,难以调试
int result = numbers.stream()
.filter(n -> n > 2)
.map(n -> n * 2)
.sorted()
.distinct()
.reduce(0, Integer::sum);
System.out.println(result);
// 好的:分步骤,清晰可读
List<Integer> filtered = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toList());
List<Integer> doubled = filtered.stream()
.map(n -> n * 2)
.collect(Collectors.toList());
int sum = doubled.stream()
.reduce(0, Integer::sum);
System.out.println(sum);
}
}
浙公网安备 33010602011771号