java8新特性------Function&Stream&Optional
文章目录
函数式编程
简介
函数式编程,或称函数程序设计、泛函编程,是一种编程范型,它将电脑运算视为函数运算,并且避免使用程式状态以及可变物件。这意味着一个函数,既可以作为其它函数的输入参数值,也可以从函数中返回值,被修改或者被分配给一个变量。
比起指令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而不是设计一个复杂的执行过程。
在java中,函数式编程有以下特征:
- 接口中有且只有一个抽象方法;
- 接口被@FunctionalInterface注解修饰;
- 使用Lambda表达式作为入参和返回值;
常用的函数式接口
-
BinaryOperator extends BiFunction<T,T,T>
表示两个相同类型的操作数进行运算,产生与操作数相同类型的结果。
javaBinaryOperator<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
javaList<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
消费型接口,且无返回值。
javaConsumer 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<T, R>
函数型接口,接收一个参数,返回一个结果。
andThen()先执行function1.apply(),再执行function2.apply();compose()则相反。javaFunction 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。
javaPredicate 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
供给型接口,提供一个返回值。
javaSupplier supplier = () -> "爱无悔 情无怨 为何倩影却成烟"; String str = (String) supplier.get(); System.out.printf("str: %s", str); // 执行结果 str: 爱无悔 情无怨 为何倩影却成烟
Stream流
简介
Stream是一个用于处理集合数据的API,它并不是集合,也不是数据结构,其本身并不存储任何元素(或其他地址值)。元素是特定类型的对象,形成一个队列,Stream并不会存储元素,而是按需计算和处理数据。Stream操作有以下特征:
-
数据源: 流的来源,可以是集合,数组,I/O资源或者其他数据源等。
-
Pipelining:Stream提供了多种方法针对流中的元素进行处理,这些方法支持链式调用形成流水线式的操作流程。每次操作都会返回一个新的流,原数据保持不变。
-
延迟处理 :在调用中间操作方法时,不会立即执行实际计算,只有执行终端操作时才会触发实际的计算。
-
函数式编程:Stream提供了一组函数式编程的方法,可以以声明的方式操作数据,避免了显式的迭代和条件判断,使代码更简洁、易读。
常用方法
当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)->数据转换->执行操作
获取想要的结果,每次转换原有Stream对象不变,返回一个新的Stream对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。stream流是一种管道流,只能被消费一次,多次消费同一个流会抛出IllegalStateException异常,链式调用是每次将上一个流传递给下一个流,实际上是生成新的流。
-
Filter(Predicate<? super T> predicate)
接收一个Predicate函数作为参数,不满足Predicate条件的会被过滤掉。
javaStream<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。
javaList<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函数将流中每个元素映射为一个流并将所有流连接成一个流。
javaList<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()来判断是否重复,并且去重。
javaList<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函数自定义排序规则。javaList<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函数,对流中每一个元素执行一个操作,返回新的流与原始流中的数据相同。
javaList<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)
截断流中的元素个数。
javaList<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个元素。
javaList<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函数,对流中每个元素执行一个操作,这是一个终端操作。
javaList<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函数,允许重用收集策略和收集操作的组合,这是一个终端操作。
javaList<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()
返回流中元素个数,这是一个终端操作。
javaList<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]。
javaList<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值,这是一个短路操作。
javaList<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值,这是一个短路操作。
javaList<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
Optional是一个容器类工具类,目的是解决NPE问题。
Optional是一个包装器类,其中包含对其他对象的引用,这样就不用显式的进行空值检测。
创建Optional对象
-
empty()
javaOptional<String> empty = Optional.empty(); System.out.println(empty); // 执行结果 Optional.empty
-
of(T value)
此处参数必须不为null,否则会报错NPE;
javaString 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对象。
javaString str = null; Optional<String> stringOptional = Optional.ofNullable(str); System.out.println(stringOptional); // 执行结果 Optional.empty
常用方法
-
isPresent()
判断一个Optional对象是否存在,如果存在则返回true,否则返回false。
javaString 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。
javaString 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函数,如果存在值则执行传入的操作。
javaOptional.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两个函数,如果存在值就执行第一个,否则就执行第二个操作。
javaOptional.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对象。
javaOptional<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。
javaOptional<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 对象合并为一个返回。
javaOptional<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则返回该值。
javaString 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则执行该操作。
javaString 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则抛出自定义异常。
javatry { Optional.ofNullable(null).orElseThrow(() -> new Exception("npe")); }catch (Exception e) { e.printStackTrace(); } // 执行结果 java.lang.Exception: npe