函数式编程,或称函数程序设计、泛函编程,是一种编程范型,它将电脑运算视为函数运算,并且避免使用程式状态以及可变物件。这意味着一个函数,既可以作为其它函数的输入参数值,也可以从函数中返回值,被修改或者被分配给一个变量。
比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。
在java中,函数式编程有以下特征:
BinaryOperator extends BiFunction
表示两个相同类型的操作数进行运算,产生与操作数相同类型的结果。
BinaryOperator<Integer> addition = (x, y) -> x + y;
BinaryOperator<Integer> subtraction = (x, y) -> x - y;
BinaryOperator<Integer> multiplication = (x, y) -> x * y;
BinaryOperator<Double> division = (x, y) -> x / y;
System.out.println("10 + 5 = " + addition.apply(10, 5));
System.out.println("10 - 5 = " + subtraction.apply(10, 5));
System.out.println("10 * 5 = " + multiplication.apply(10, 5));
System.out.println("10.0 / 2.0 = " + division.apply(10.0, 2.0));
// 执行结果
10 + 5 = 15
10 - 5 = 5
10 * 5 = 50
10.0 / 2.0 = 5.0
List<User> list0 = Arrays.asList(
User.builder().name("Emma Watson").age(18).sex("女").build(),
User.builder().name("Angelina Jolie").age(19).sex("女").build(),
User.builder().name("Emilia Clarke").age(20).sex("女").build(),
User.builder().name("Anna Kendrick").age(21).sex("女").build(),
User.builder().name("Tony").age(21).sex("男").build(),
User.builder().name("Tom").age(22).sex("男").build(),
User.builder().name("Jerry").age(23).sex("男").build(),
User.builder().name("Marks").age(24).sex("男").build()
);
Comparator<User> comparator = Comparator.comparing(User::getAge);
Map<String, Optional<User>> map = list0.stream().collect(Collectors.groupingBy(User::getSex,
Collectors.reducing(BinaryOperator.maxBy(comparator))));
map.entrySet().forEach(entry -> {
System.out.printf("key: %s + value: %s \n", entry.getKey(), entry.getValue());
});
// 执行结果
key: 女 + value: Optional[User(name=Anna Kendrick, sex=女, age=21)]
key: 男 + value: Optional[User(name=Marks, sex=男, age=24)]
Consumer
消费型接口,且无返回值。
Consumer consumer1 = s -> {
s += " is good day!";
System.out.println(s);
};
Consumer consumer2 = s -> {
s = "Yesterday is a history, tomorrow is a mystery, but today is a gift, that is why it is called Present.";
System.out.println(s);
};
consumer1.andThen(consumer2).accept("Today");
// 执行结果
Today is good day!
Yesterday is a history, tomorrow is a mystery, but today is a gift, that is why it is called Present.
Function
函数型接口,接收一个参数,返回一个结果。
andThen()先执行function1.apply(),再执行function2.apply();compose()则相反。
Function function1 = a -> new StringBuffer(a.toString()).reverse().toString();
Function function2 = a -> a.toString().toUpperCase();
String str1 = (String) function1.andThen(function2).apply("hello world");
String str2 = (String) function1.compose(function2).apply("hello world");
System.out.printf("str1: %s\n", str1);
System.out.printf("str2: %s\n", str2);
// 执行结果
str1: DLROW OLLEH
str2: DLROW OLLEH
Predicate
断言型接口,如果满足条件则返回true,否则返回false。
Predicate predicate1 = s -> String.valueOf(s).length() > 5;
Predicate predicate2 = s -> String.valueOf(s).startsWith("划");
boolean flag = predicate1.and(predicate2).test("划过天空的流星");
System.out.printf("flag: %s", flag);
// 执行结果
flag: true
Supplier
供给型接口,提供一个返回值。
Supplier supplier = () -> "爱无悔 情无怨 为何倩影却成烟";
String str = (String) supplier.get();
System.out.printf("str: %s", str);
// 执行结果
str: 爱无悔 情无怨 为何倩影却成烟
Stream是一个用于处理集合数据的API,它并不是集合,也不是数据结构,其本身并不存储任何元素(或其他地址值)。元素是特定类型的对象,形成一个队列,Stream并不会存储元素,而是按需计算和处理数据。Stream操作有以下特征:
数据源: 流的来源,可以是集合,数组,I/O资源或者其他数据源等。
Pipelining:Stream提供了多种方法针对流中的元素进行处理,这些方法支持链式调用形成流水线式的操作流程。每次操作都会返回一个新的流,原数据保持不变。
延迟处理:在调用中间操作方法时,不会立即执行实际计算,只有执行终端操作时才会触发实际的计算。
函数式编程:Stream提供了一组函数式编程的方法,可以以声明的方式操作数据,避免了显式的迭代和条件判断,使代码更简洁、易读。
当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)->数据转换->执行操作
获取想要的结果,每次转换原有Stream对象不变,返回一个新的Stream对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。stream流是一种管道流,只能被消费一次,多次消费同一个流会抛出IllegalStateException异常,链式调用是每次将上一个流传递给下一个流,实际上是生成新的流。
Filter(Predicate super T> predicate)
接收一个Predicate函数作为参数,不满足Predicate条件的会被过滤掉。
Stream<String> stream = Stream.of("123", "132", "213", "231", "312", "321");
stream.filter(e -> e.startsWith("3")).forEach(System.out::println);
stream.filter(Objects::nonNull);
// 执行结果
312
321
// 多次操作一个流抛出异常
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
at java.base/java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203)
at java.base/java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:96)
at java.base/java.util.stream.ReferencePipeline$StatelessOp.<init>(ReferencePipeline.java:800)
at java.base/java.util.stream.ReferencePipeline$2.<init>(ReferencePipeline.java:167)
at java.base/java.util.stream.ReferencePipeline.filter(ReferencePipeline.java:166)
map(Function super T, ? extends R> mapper)
接收一个Function函数作为参数,对Stream中的每个元素进行映射转换,返回新的Stream。
List<String> list0 = Arrays.asList("a", "b", "c", "d", "e", "f");
list0.stream().map(e -> (int) e.charAt(0)).forEach(System.out::println);
// 执行结果
97
98
99
100
101
102
flatMap(Function super T, ? extends Stream extends R>> mapper)
扁平映射,接收一个Function函数将流中每个元素映射为一个流并将所有流连接成一个流。
List<List<Integer>> list1 = Arrays.asList(
Arrays.asList(1, 2, 3),
Arrays.asList(4, 5, 6),
Arrays.asList(7, 8, 9)
);
list1.stream().flatMap(List::stream).forEach(System.out::println);
// 执行结果
123456789
distinct()
根据流中元素的hashCode()和equals()来判断是否重复,并且去重。
List<Integer> list2 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1);
list2.stream().distinct().forEach(System.out::print);
// 执行结果
1234567
sorted() / sorted(Comparator super T> comparator)
用于对流中元素进行排序,默认是按照自然顺序排序,对于无序流不提供稳定性保证。
也可以接收一个Comparator函数自定义排序规则。
List<Integer> list3 = Arrays.asList(5, 3, 1, 4, 2, 6, 7);
list3.stream().sorted().forEach(System.out::print);
System.out.println();
list3.stream().sorted(((o1, o2) -> {
return o2.compareTo(o1);
})).forEach(System.out::print);
// 执行结果
1234567
7654321
peek(Consumer super T> action)
类似forEach方法,区别在于这不是终端操作,接收一个Consum函数,对流中每一个元素执行一个操作,返回新的流与原始流中的数据相同。
List<Integer> list4 = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list4.stream().peek(e -> {
e = (e + 3) * 7;
System.out.printf("value: %d", e);
}).peek(el -> {
System.out.printf(" || %d \n", el);
}).collect(Collectors.toList());
// 执行结果
value: 28 || 1
value: 35 || 2
value: 42 || 3
value: 49 || 4
value: 56 || 5
value: 63 || 6
value: 70 || 7
limit(long maxSize)
截断流中的元素个数。
List<Integer> list5 = Arrays.asList(5, 3, 1, 4, 2, 6, 7);
list5.stream().limit(3).sorted().forEach(System.out::print);
// 执行结果
531
skip(long n)
忽略流中前n个元素。
List<Integer> list6 = Arrays.asList(5, 3, 1, 4, 2, 6, 7);
list6.stream().skip(3).forEach(System.out::print);
// 执行结果
4267
forEach(Consumer super T> action)
接收一个Consumer函数,对流中每个元素执行一个操作,这是一个终端操作。
List<Integer> list7 = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list7.stream().forEach(e -> {
e *= 2;
System.out.printf("%d ", e);
});
// 执行结果
2 4 6 8 10 12 14
collect(Collector super T, A, R> collector)
接收一个Collector函数,允许重用收集策略和收集操作的组合,这是一个终端操作。
List<Person> list8 = Arrays.asList(
Person.builder().name("Tom").sex("男").build(),
Person.builder().name("Jack").sex("男").build(),
Person.builder().name("Susan").sex("女").build(),
Person.builder().name("Lilith").sex("女").build()
);
Map<String, Map<String, List<Person>>> map = list8.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getName)));
map.entrySet().forEach(entry -> {
System.out.printf("%s:%s \n", entry.getKey(), entry.getValue());
});
// 执行结果
女:{Lilith=[Person(name=Lilith, sex=女)], Susan=[Person(name=Susan, sex=女)]}
男:{Tom=[Person(name=Tom, sex=男)], Jack=[Person(name=Jack, sex=男)]}
count()
返回流中元素个数,这是一个终端操作。
List<Integer> list9 = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
long count = list9.stream().count();
System.out.printf("count:%d", count);
// 执行结果
count:7
anyMatch(Predicate super T> predicate) / allMatch(Predicate super T> predicate) / noneMatch(Predicate super T> predicate)
anyMatch方法用于判断流中元素是否存在至少一个满足给定的条件,返回boolean值,这是一个短路操作[^1]。
List<String> list10 = Arrays.asList("12", "23", "34", "45", "56", "67");
boolean result = list10.stream().anyMatch(s -> s.length() > 3);
System.out.printf("result: %s", result);
// 执行结果
result: false
allMatch方法用于判断流中元素是否全部满足给定的条件,返回boolean值,这是一个短路操作。
List<String> list10 = Arrays.asList("12", "23", "34", "45", "56", "67");
result = list10.stream().allMatch(s -> s.length() >= 2);
System.out.printf("result: %s", result);
// 执行结果
result: true
noneMatch方法用于判断流中元素是否没有给定的条件,返回boolean值,这是一个短路操作。
List<String> list10 = Arrays.asList("12", "23", "34", "45", "56", "67");
result = list10.stream().noneMatch(s -> s.length() > 2);
System.out.printf("result: %s", result);
// 执行结果
result: true
短路操作:对于流中的元素,只要满足条件之后即可返回,无需操作所有元素。
Optional是一个容器类工具类,目的是解决NPE问题。
Optional是一个包装器类,其中包含对其他对象的引用,这样就不用显式的进行空值检测。
empty()
Optional<String> empty = Optional.empty();
System.out.println(empty);
// 执行结果
Optional.empty
of(T value)
此处参数必须不为null,否则会报错NPE;
String str = null;
Optional<String> stringOptional = Optional.of(str);
// 执行结果
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:208)
at java.base/java.util.Optional.of(Optional.java:113)
ofNullable(T value)
如果参数为null,则会返回空的Optional对象。
String str = null;
Optional<String> stringOptional = Optional.ofNullable(str);
System.out.println(stringOptional);
// 执行结果
Optional.empty
isPresent()
判断一个Optional对象是否存在,如果存在则返回true,否则返回false。
String str = null;
Optional<String> stringOptional = Optional.ofNullable(str);
System.out.println(stringOptional.isPresent());
str = new String("Hello World");
System.out.println(Optional.ofNullable(str).isPresent());
// 执行结果
false
true
isEmpty()
类似isPresen(),如果对象存在就返回false,否则返回true。
String str = null;
Optional<String> stringOptional = Optional.ofNullable(str);
System.out.println(stringOptional.isEmpty());
str = new String("Hello World");
System.out.println(Optional.ofNullable(str).isEmpty());
// 执行结果
true
false
ifPresent(Consumer super T> action)
接收一个Consumer函数,如果存在值则执行传入的操作。
Optional.ofNullable("Hello World").ifPresent(s -> System.out.printf("%s!", s));
Optional.ofNullable(null).ifPresent(s -> System.out.printf("%s!", s));
// 执行结果
Hello World!
ifPresentOrElse(Consumer super T> action, Runnable emptyAction)
接收Consumer和Rnnable两个函数,如果存在值就执行第一个,否则就执行第二个操作。
Optional.ofNullable("Hello World").ifPresentOrElse(s -> System.out.printf("%s!\n", s), () -> System.out.println("value不存在"));
Optional.ofNullable(null).ifPresentOrElse(s -> System.out.printf("%s!", s), () -> System.out.println("value不存在"));
// 执行结果
Hello World!
value不存在
filter(Predicate super T> predicate)
接收一个Predicate函数,如果满足条件则返回包含该对象的Optional对象,否则返回一个空的Optional对象。
Optional<String> optional0 = Optional.ofNullable("Hello World").filter(s -> s.length() > 5);
Optional<String> optional1 = Optional.ofNullable("Hello World").filter(s -> s.length() > 11);
System.out.printf("optional0: %s\n", optional0);
System.out.printf("optional1: %s\n", optional1);
// 执行结果
optional0: Optional[Hello World]
optional1: Optional.empty
map(Function super T, ? extends U> mapper)
接收一个Function函数,如果值存在则返回一个包含映射结果值的Optional,否则返回一个空的Optional。
Optional<String> nameOptional = Optional.ofNullable(new Person("Jerry", "男")).map(Person::getName);
System.out.printf("nameOptional: %s", nameOptional);
// 执行结果
nameOptional: Optional[Jerry]
flatMap(Function super T, ? extends Optional extends U>> mapper)
接收一个Function的函数,将 Optional 对象中的值映射为另一个 Optional 对象,然后将两个 Optional 对象合并为一个返回。
Optional<String> nameUpper = Optional.ofNullable(new Person("Jerry", "男")).flatMap(e -> Optional.ofNullable(e.getName().toUpperCase()));
System.out.printf("nameUpper: %s", nameUpper);
// 执行结果
nameUpper: Optional[JERRY]
orElse(T other)
如果Optional的对象是null则返回该值。
String string = (String) Optional.ofNullable(null).orElse("Hello World");
System.out.printf("string: %s", string);
// 执行结果
string: Hello World
orElseGet(Supplier extends T> supplier)
接收一个Supplier函数,如果Optional的对象是null则执行该操作。
String name = (String) Optional.ofNullable(null).orElseGet(new Person("Jerry", "男")::getName);
System.out.printf("name: %s", name);
// 执行结果
name: Jerry
orElseThrow(Supplier extends X> exceptionSupplier)
接收一个Supplier函数,如果Optional的对象是null则抛出自定义异常。
try {
Optional.ofNullable(null).orElseThrow(() -> new Exception("npe"));
}catch (Exception e) {
e.printStackTrace();
}
// 执行结果
java.lang.Exception: npe