JDK1.8新特性(一) ----Lambda表达式、Stream API…
2019-12-23 16:03:03来源:博客园 阅读 ()
JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用
jdk1.8新特性知识点:- Lambda表达式
- Stream API
- 函数式接口
- 方法引用和构造器调用
- 接口中的默认方法和静态方法
- 新时间日期API
- default
现在JDK1.8给我们提供了新的方式Lambda表达式,比上边的两个例子编写的代码更为简单更简介,下面我们来看一看怎么比上边的代码更简单。
场景一:附图 场景二:附图下边是Lmabda表达式的语法总结: 口诀:左右遇一省括号,左侧推断类型省 注:当一个接口中存在多个抽象方法时,如果使用lambda表达式,并不能智能匹配对应的抽象方法,因此引入了函数式接口的概念。 先介绍一下Stream API,上边提到了Stream API,挨着写,下一个介绍函数式接口。 Stream API: Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简单来说,Stream API 提供了一种高效且易于使用的处理数据的方式。 注意:1.Stream不会自己存储元素 2.Stream不会改变源对象,相反他们会返回一个持有新结果集的Stream对象。 3.Stream的操作是延迟执行的,这意味着他们会等到需要结果的时候才执行 4. 只有当作终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”、“延迟加载” 5. 每一个Stream流只能操作一次,如果第二次操作会报错stream has already been operated upon or closed Stream API的执行流程: 直接上代码: 1.创建流Stream 2.中间操作 3.终止操作
1 //3.终止操作 2 /** 3 * 查找和匹配 4 * allMatch-检查是否匹配所有元素 5 * anyMatch-检查是否至少匹配一个元素 6 * noneMatch-检查是否没有匹配所有元素 7 * findFirst-返回第一个元素 8 * findAny-返回当前流中的任意元素 9 * count-返回流中元素的总个数 10 * max-返回流中最大值 11 * min-返回流中最小值 12 */ 13 //3.1:allMatch检查是否匹配所有元素是否都成立,都成立返回true 否则返回false 14 Stream<Map<String, Object>> stream2 = maps.stream(); 15 boolean a = stream2.allMatch(x -> Integer.valueOf(x.get("age").toString()) > 16); 16 System.err.println("结果:"+a); //false 17 //3.2:anyMatch检查是否至少匹配一个元素,只要有一个成立就返回true 18 Stream<Map<String, Object>> stream3 = maps.stream(); 19 boolean b = stream3.anyMatch(x -> Integer.valueOf(x.get("age").toString()) > 16); 20 System.err.println("结果:"+b); //true 21 //3.3:noneMatch检查是否没有匹配所有元素,因为有成立的所以有匹配的元素,估 不成立 22 Stream<Map<String, Object>> stream4 = maps.stream(); 23 boolean c = stream4.noneMatch(x -> Integer.valueOf(x.get("age").toString()) > 16); 24 System.err.println("结果:"+c); //false 25 //3.4:findFirst返回第一个元素,按照年龄从小到大排序返回第一个元素 26 Stream<Map<String, Object>> stream5 = maps.stream(); 27 Map<String, Object> first = stream5.sorted((x,y) -> Integer.compare(Integer.valueOf(x.get("age") 28 .toString()),Integer.valueOf(y.get("age").toString()))).findFirst().get(); 29 System.err.println(first.toString());//{sex=女, name=小红, age=16} 30 //3.5:findAny-返回当前流中的任意元素 31 Stream<Map<String, Object>> stream6 = maps.stream(); 32 Map<String, Object> map = stream6.sorted((x,y) -> Integer.compare(Integer.valueOf(y.get("age") 33 .toString()),Integer.valueOf(x.get("age").toString()))).findAny().get(); 34 //多次测试返回固定是这个,感觉因该是内部有一个算法排序然后返回其中固定某个 {sex=男, name=小明, age=18} 35 //排序之后返回的永远是第一个 36 System.err.println(map.toString()); 37 //3.6:返回流中元素的总个数 38 Stream<Map<String, Object>> stream7 = maps.stream(); 39 long count = stream7.count(); 40 System.err.println("长度为:"+count); // 长度为:3 41 //TODO 最大最小就不测试了,自己可以试试
还有功能比较强大的两个终止操作 reduce和collect
reduce操作: reduce:(T identity,BinaryOperator)/reduce(BinaryOperator)-可以将流中元素反复结合起来,得到一个值1 /** 2 * reduce :规约操作 3 * 计算和 4 * 计算结果作为x,再从数组中取出新值作为y,进行下一步计算 5 * 结果在加上0 是最后的结果 6 */ 7 List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); 8 Integer count2 = list.stream().reduce(0, (x, y) -> x + y); 9 System.out.println(count2); 10 11 Stream<Map<String, Object>> stream8 = maps.stream(); 12 //计算总年龄 也可以是浮点型数据 将Integer 换成Double就ok 13 Optional<Integer> op = stream8.map(m -> Integer.valueOf(String.valueOf(m.get("age")))) 14 .reduce(Integer::sum); 15 System.err.println(op.get()); //54collect操作:Collect-将流转换为其他形式,接收一个Collection接口的实现,用于给Stream中元素做汇总的方法,转换为一个新的集合或者对象
1 /** 2 * collect操作:Collect-将流转换为其他形式, 3 * 接收一个Collection接口的实现,用于给Stream中元素做汇总的方法 4 * Collectors.toList()/toSet() 5 */ 6 Set<Integer> ageList = list.stream().collect(Collectors.toSet()); 7 ageList.stream().forEach(System.out::println); 8 //取名字,封装成hashset 9 HashSet<Integer> hs = list.stream() 10 .collect(Collectors.toCollection(HashSet::new)); 11 System.err.println(hs.toString());
函数式接口:
函数式接口的提出是为了给Lambda表达式的使用提供更好的支持。什么是函数式接口? 简单来说就是只定义了一个抽象方法的接口(Object类的public方法除外),就是函数式接口,并且还提供了注解:@FunctionalInterface 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 函数式接口可以被隐式转换为 lambda 表达式。 Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。 如定义了一个函数式接口如下:
1 @FunctionalInterfaceinterface GreetingService 2 { 3 void sayMessage(String message); 4 } 5 6 // 那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的): 7 GreetingService greetService1 = message -> System.out.println("Hello " + message);常见的四大函数式接口有: Consumer 《T》:消费型接口,有参无返回值 Supplier 《T》:供给型接口,无参有返回值 Function 《T,R》:函数式接口,有参有返回值 Predicate《T》:断言型接口,有参有返回值,返回值是boolean类型
1 /** 2 * @MethodName: functionInterface 3 * @Description: 四大函数式接口练习 4 * @param 5 * @return 6 * @author rongrong 7 * @date 2019-12-23 8 */ 9 public void functionInterface(){ 10 /** 11 * 1.Consumer 《T》:消费型接口,有参无返回值 12 * 打印: 13 * 222222 14 * hello 15 */ 16 changeStr("hello",(str) -> System.err.println(str)); 17 18 /** 19 * 2.Supplier 《T》:供给型接口,无参有返回值 20 * 打印: 21 * 111111 22 * str 23 */ 24 String value = getValue(() -> "str"); 25 System.err.println(value); 26 27 /** 28 * 3. Function 《T,R》::函数式接口,有参有返回值 29 * 打印: 30 * 333333 31 * 20000 32 */ 33 Long aLong = changeNum(100L, x -> x * 200); 34 System.err.println(aLong); 35 /** 36 * Predicate《T》: 断言型接口,有参有返回值,返回值是boolean类型 37 * 打印: 38 * true 39 */ 40 boolean rongrong = changeBoolean("rongrong", x -> x.equals("rongrong")); 41 System.err.println(rongrong); 42 43 } 44 45 /** 46 * Consumer<T> 消费型接口 47 * @param str 48 * @param con 49 */ 50 public void changeStr(String str, Consumer<String> con){ 51 System.err.println("222222"); 52 con.accept(str); 53 } 54 55 /** 56 * Supplier<T> 供给型接口 57 * @param sup 58 * @return 59 */ 60 public String getValue(Supplier<String> sup){ 61 System.err.println("111111"); 62 return sup.get(); 63 } 64 65 /** 66 * Function<T,R> 函数式接口 67 * @param num 68 * @param fun 69 * @return 70 */ 71 public Long changeNum(Long num, Function<Long, Long> fun){ 72 System.err.println("333333"); 73 return fun.apply(num); 74 } 75 76 /** 77 * Predicate<T> 断言型接口 78 * @param str 79 * @param pre 80 * @return 81 */ 82 public boolean changeBoolean(String str, Predicate<String> pre){ 83 return pre.test(str); 84 }
在四大核心函数式接口基础上,还提供了诸如BiFunction、BinaryOperation、toIntFunction等扩展的函数式接口,都是在这四种函数式接口上扩展而来的,不做赘述。
总结:函数式接口的提出是为了让我们更加方便的使用lambda表达式,不需要自己再手动创建一个函数式接口,直接拿来用就好了,详细接口描述在下边。 方法引用: 若lambda体中的内容有方法已经实现了,那么可以使用“方法引用”也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单 (a) 方法引用 三种表现形式: 1. 对象:实例方法名 2. 类::静态方法名 3. 类::实例方法名 (lambda参数列表中第一个参数是实例方法的调用 者,第二个参数是实例方法的参数时可用)1 /** 2 *注意: 3 * 1.lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致! 4 * 2.若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method 5 * 下边写的例子 上边是不简化时的写法,下边的是对应的简化写法,就是方法引用 6 */ 7 8 //100 9 //200 10 Consumer<Integer> con = (x) -> System.out.println(x); 11 con.accept(100); 12 // 方法引用-对象::实例方法 13 Consumer<Integer> con2 = System.out::println; 14 con2.accept(200); 15 16 // 方法引用-类名::静态方法名 17 BiFunction<Integer, Integer, Integer> biFun = (x, y) -> Integer.compare(x, y); 18 Integer apply = biFun.apply(100, 200); 19 BiFunction<Integer, Integer, Integer> biFun2 = Integer::compare; 20 Integer result = biFun2.apply(100, 200); 21 //-1:-1 22 System.err.println(apply + ":" + result); 23 24 // 方法引用-类名::实例方法名 25 BiFunction<String, String, Boolean> fun1 = (str1, str2) -> str1.equals(str2); 26 Boolean apply1 = fun1.apply("rong", "rong"); 27 BiFunction<String, String, Boolean> fun2 = String::equals; 28 Boolean result2 = fun2.apply("hello", "world"); 29 //true:false 30 System.out.println(apply1 + ":" + result2);(b)构造器引用 格式:ClassName::new
1 // 构造方法引用 类名::new 2 Supplier<String> sup = () -> new String(); 3 System.out.println(sup.get()); 4 Supplier<String> sup2 = String::new; 5 System.out.println(sup2.get()); 6 7 // 构造方法引用 类名::new (带一个参数) 8 //x 代表是传进去的参数,也就是泛型中的Integer类型 9 //new String(...) 代表泛型中的String类型 10 Function<Integer, String> fun = x -> new String(String.valueOf(x)); 11 System.err.println(fun.apply(100)); 12 Function<String, String> fun3 = String::new; 13 System.out.println(fun3.apply("100"));(c)数组引用 格式:Type[]::new
1 // 数组引用 2 Function<Integer, String[]> arrayFun = (x) -> new String[x]; 3 Function<Integer, String[]> arrayFun2 = String[]::new; 4 //给String数组设置了两个长度。但是值是null 5 String[] strArray = arrayFun2.apply(2); 6 Arrays.stream(strArray).forEach(System.out::println);
序号 | 接口 & 描述 |
1 | BiConsumer<T,U> 代表了一个接受两个输入参数的操作,并且不返回任何结果 |
2 | BiFunction<T,U,R> 代表了一个接受两个输入参数的方法,并且返回一个结果 |
3 | BinaryOperator<T> 代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果 |
4 | BiPredicate<T,U> 代表了一个两个参数的boolean值方法 |
5 | BooleanSupplier 代表了boolean值结果的提供方 |
6 | Consumer<T> 代表了接受一个输入参数并且无返回的操作 |
7 | DoubleBinaryOperator 代表了作用于两个double值操作符的操作,并且返回了一个double值的结果。 |
8 | DoubleConsumer 代表一个接受double值参数的操作,并且不返回结果。 |
9 | DoubleFunction<R> 代表接受一个double值参数的方法,并且返回结果 |
10 | DoublePredicate 代表一个拥有double值参数的boolean值方法 |
11 | DoubleSupplier 代表一个double值结构的提供方 |
12 | DoubleToIntFunction 接受一个double类型输入,返回一个int类型结果。 |
13 | DoubleToLongFunction 接受一个double类型输入,返回一个long类型结果 |
14 | DoubleUnaryOperator 接受一个参数同为类型double,返回值类型也为double 。 |
15 | Function<T,R> 接受一个输入参数,返回一个结果。 |
16 | IntBinaryOperator 接受两个参数同为类型int,返回值类型也为int 。 |
17 | IntConsumer 接受一个int类型的输入参数,无返回值 。 |
18 | IntFunction<R> 接受一个int类型输入参数,返回一个结果 。 |
19 | IntPredicate :接受一个int输入参数,返回一个布尔值的结果。 |
20 | IntSupplier 无参数,返回一个int类型结果。 |
21 | IntToDoubleFunction 接受一个int类型输入,返回一个double类型结果 。 |
22 | IntToLongFunction 接受一个int类型输入,返回一个long类型结果。 |
23 | IntUnaryOperator 接受一个参数同为类型int,返回值类型也为int 。 |
24 | LongBinaryOperator 接受两个参数同为类型long,返回值类型也为long。 |
25 | LongConsumer 接受一个long类型的输入参数,无返回值。 |
26 | LongFunction<R> 接受一个long类型输入参数,返回一个结果。 |
27 | LongPredicate R接受一个long输入参数,返回一个布尔值类型结果。 |
28 | LongSupplier 无参数,返回一个结果long类型的值。 |
29 | LongToDoubleFunction 接受一个long类型输入,返回一个double类型结果。 |
30 | LongToIntFunction 接受一个long类型输入,返回一个int类型结果。 |
31 | LongUnaryOperator 接受一个参数同为类型long,返回值类型也为long。 |
32 | ObjDoubleConsumer<T> 接受一个object类型和一个double类型的输入参数,无返回值。 |
33 | ObjIntConsumer<T> 接受一个object类型和一个int类型的输入参数,无返回值。 |
34 | ObjLongConsumer<T> 接受一个object类型和一个long类型的输入参数,无返回值。 |
35 | Predicate<T> 接受一个输入参数,返回一个布尔值结果。 |
36 | Supplier<T> 无参数,返回一个结果。 |
37 | ToDoubleBiFunction<T,U> 接受两个输入参数,返回一个double类型结果 |
38 | ToDoubleFunction<T> 接受一个输入参数,返回一个double类型结果 |
39 | ToIntBiFunction<T,U> 接受两个输入参数,返回一个int类型结果。 |
40 | ToIntFunction<T> 接受一个输入参数,返回一个int类型结果。 |
41 | ToLongBiFunction<T,U> 接受两个输入参数,返回一个long类型结果。 |
42 | ToLongFunction<T> 接受一个输入参数,返回一个long类型结果。 |
43 | UnaryOperator<T> 接受一个参数为类型T,返回值类型也为T。 |
原文链接:https://www.cnblogs.com/rrong/p/12088903.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Spring Boot 2.3.0 新特性Redis 拓扑动态感应 2020-06-11
- 今天来介绍java 各版本的新特性,一篇文章让你了解 2020-06-10
- Spring Boot 2.3 新特性优雅停机详解 2020-06-08
- 原创 Spring Boot 2.3 新特性分层JAR 2020-06-08
- MyBatis缓存特性详解 2020-06-03
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash