博客
关于我
Day79.Java8的其他新特性复习 -Java8其他新特性
阅读量:341 次
发布时间:2019-03-04

本文共 17165 字,大约阅读时间需要 57 分钟。

Java8的其他新特性复习

Java8新特性概述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2fZ4fU8c-1603378957381)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022213053883.png)]

Lambda表达式

1.Lambda表达式使用前后对比:

举例一:

@Testpublic void test1(){       //之前写法    Runnable r1 = new Runnable() {           @Override        public void run() {               System.out.println("我爱温州五马街");        }    };    r1.run();    System.out.println("===================================================");    //Lambda表达式写法   ->    Runnable r2 = () -> System.out.println("我爱温州江心屿");    r2.run();}

举例二:

@Testpublic void test2(){       //之前的写法    Comparator
com1 = new Comparator
() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; int c1 = com1.compare(13, 18); System.out.println(c1); System.out.println("==============================================="); //Lambda表达式写法 -> Comparator
com2 = (o1,o2) -> Integer.compare(o1,o2); int c2 = com2.compare(123, 18); System.out.println(c2); System.out.println("==============================================="); //方法引用写法 :: Comparator
com3 = Integer :: compare; int c3 = com3.compare(123, 18); System.out.println(c3);}

2.Lambda表达式的基本语法:

* 1.举例: (o1,o2) -> Integer.compare(o1,o2);* 2.格式:*      -> :lambda操作符 或 箭头操作符*      ->的左边: lambda形参列表   (其实就是接口中的抽象方法的形参列表)*      ->的右边: lambda体 (其实就是重写的抽象方法的方法体)

3.如何使用:分为六种情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FcYjdTxD-1603378957388)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022214308453.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSsrSQ6N-1603378957391)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022214314628.png)]

总结六种情况

*      ->左边: lambda形参列表可以省略(类型推断);*             如果参数列表没有参数,则保留小括号: (s) ->*             如果参数列表只有一个参数,其一对小括号也可省略: s ->*             如果参数列表有两个或两个以上的参数,则保留小括号和多个参数: (o1,o2,...) ->*      ->右边: lambda体应该使用一对{}包裹;*             如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return关键字

.

函数式接口

1.函数式接口的使用说明

*   如果一个接口中,只声明了一个抽象方法,则此接口就成为函数式接口*   我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检验它是否是一个函数式接口。*   所以以前用匿名实现类表示的现在都可以用Lambda表达式 *  Lambda表达式的本质: 作为接口的实例 *  一个接口仅有一个待实现方法

2.Java8中关于Lambda表达式提供的4个基本函数式接口:

具体使用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gNsAboQZ-1603378957402)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022215657275.png)]

3.总结

何时使用Lambda表达式?

当需要对一个函数式接口实例化的时候,可以使用Lambda表达式。

何时使用给定的函数式接口?

如果我们开发中需要定义一个函数式接口,

首先看看在已有的jdk提供的函数式接口是否提供了能满足需求的函数式接口。

如果有,则直接调用即可。不需要自己再自定义

方法引用

1.理解:

方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就 是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向 一个方法。

2.使用情景:

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!

3.格式

使用的格式:  类(或对象) :: 方法名

4.分为如下的三种情况:

*    情况1) 对象 :: 非静态方法(实例方法)*    情况2) 类  :: 静态方法**    情况3) 类  :: 非静态方法

5.要求:

要求接口中的抽象方法的形参列表和返回值类型 与 方法引用的方法的形参列表和返回值类型 相同(针对于情况1与情况2)当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName

6.使用建议:

如果给函数式接口提供实例,恰好满足方法引用的使用情景,大家就可以考虑方法引用给函数式接口提供实例。

如果大家不熟悉方法引用,那么还可以使用Lambda表达。

7.使用举例

public class MethodRefTest {      // 情况1:对象 :: 实例方法   //Consumer中的void accept(T t)   //PrintStream中的void println(T t)   @Test   public void test1() {         //Lambda表达式写法      Consumer
con1 = str -> System.out.println(str); con1.accept("温州"); System.out.println("===============================================");//分割线 //方法引用写法 PrintStream ps = System.out; Consumer
con2 = ps :: println; con2.accept("wenzhou"); } //Supplier中的T get() //Employee中的String getName() @Test public void test2() { //Lambda表达式写法 Employee emp = new Employee(1001,"阿昌",23,5800); Supplier
sup1 = () -> emp.getName(); System.out.println(sup1.get());//阿昌 System.out.println("==============================================");//分割线 //方法引用写法 Supplier
sup2 = emp ::getName; System.out.println(sup2.get());//阿昌 } // 情况2:类 :: 静态方法 //Comparator中的int compare(T t1,T t2) //Integer中的int compare(T t1,T t2) @Test public void test3() { //Lambda表达式写法 Comparator
com1 = (t1,t2) -> Integer.compare(t1,t2); System.out.println(com1.compare(12, 56)); System.out.println("==============================================");//分割线 //方法引用写法 Comparator
com2 = Integer::compare; System.out.println(com2.compare(76, 21)); } //Function中的R apply(T t) //Math中的Long round(Double d) @Test public void test4() { //Lambda表达式写法 Function
fun1 = d -> Math.round(d); System.out.println(fun1.apply(3.14)); System.out.println("==============================================");//分割线 //方法引用的写法 Function
fun2 = Math :: round; System.out.println(fun2.apply(5.68)); } // 情况3:类 :: 实例方法 (有难度) // Comparator中的int comapre(T t1,T t2) // String中的int t1.compareTo(t2) @Test public void test5() { //Lambda表达式写法 Comparator
com1 = (s1,s2) -> s1.compareTo(s2); System.out.println(com1.compare("abc","obj")); System.out.println("==============================================");//分割线 //方法引用的写法 Comparator
com2 = String :: compareTo; System.out.println(com2.compare("abc","abd")); } //BiPredicate中的boolean test(T t1, T t2); //String中的boolean t1.equals(t2) @Test public void test6() { //Lambda表达式写法 BiPredicate
bip1 = (s1,s2) -> s1.equals(s2); System.out.println(bip1.test("abc","abc")); System.out.println("==============================================");//分割线 //方法引用的写法 BiPredicate
bip2 = String ::equals; System.out.println(bip2.test("ifs", "sfo")); } // Function中的R apply(T t) // Employee中的String getName(); @Test public void test7() { //Lambda表达式写法 Function
func1 = e1 -> e1.getName(); System.out.println(func1.apply(new Employee(1002,"小次郎",20,6500))); System.out.println("==============================================");//分割线 //方法引用的写法 Function
func2 = Employee::getName; System.out.println(func2.apply(new Employee(1003, "大裂郎", 41, 200))); }}

构造器引用与数组引用

1.构造器引用格式:

类名 :: new

2.构造器引用使用要求:

*      和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。*      抽象方法的返回值类型即为构造器所属的类的类型

3.构造器引用举例:

//原始写法       Supplier
sup0 = new Supplier
() { @Override public Employee get() { return new Employee(); } }; System.out.println(sup0.get()); System.out.println("==========================================");//分割线 //Lambda表达式写法 Supplier
sup1 = () -> new Employee(); System.out.println(sup1.get()); System.out.println("==========================================");//分割线 //构造器引用写法 Supplier
sup2 = Employee::new; System.out.println(sup2.get());}//Function中的R apply(T t) @Test public void test2(){ //Lambda表达式写法 Function
fun1 = id -> new Employee(id); Employee employee = fun1.apply(1001); System.out.println(employee); System.out.println("==========================================");//分割线 //构造器引用写法 Function
fun2 = Employee::new; Employee employee1 = fun2.apply(1002); System.out.println(employee1);}//BiFunction中的R apply(T t,U u) @Test public void test3(){ //Lambda表达式写法 BiFunction
bif1 = (id,str) -> new Employee(id,str); Employee employee = bif1.apply(1001, "张薇"); System.out.println(employee); System.out.println("==========================================");//分割线 //构造器引用写法 BiFunction
bif2 = Employee::new; Employee employee1 = bif2.apply(1002, "刘芳"); System.out.println(employee1); }

4.数组引用格式:

数组类型[] :: new

5.数组引用举例:

//数组引用   //Function中的R apply(T t)   @Test   public void test4(){          //Lambda表达式写法       Function
func1 = length -> new String[length]; String[] arr1 = func1.apply(8); System.out.println(Arrays.toString(arr1)); System.out.println("==========================================");//分割线 //数组引用的写法 Function
func2 = String[] :: new; String[] arr2 = func2.apply(5); System.out.println(Arrays.toString(arr2)); }

.

Stream API

1.Stream API的理解:

*     Stream关注的是对数据的运算,与CPU打交道*     集合关注的是数据的存储,与内存打交道**	  Java8提供了一套api,使用这套api可以对内存中的数据进行过滤、排序、映射、归约等操作。类似于sql对数据库表的操作

2.注意点:

*     Stream 自己不会储存元素。*     Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。*     Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行

3.Stream的使用流程:

*     ① Stream的实例化*     ② 一系列的中间操作(过滤、映射、...)*     ③ 终止操作

4.使用流程的注意点:

*     ①一个中间操作链,对数据源的数据进行处理*     ②一旦执行终止操作,就执行中间操作链,并产生结果。之后,此Stream不能再被使用

5.步骤一: Stream实例化

创建Stream的四种方式创建Stream方式一: 通过集合	//创建Stream方式一: 通过集合    @Test    public void test1(){           List
employees = EmployeeData.getEmployees();// default Stream
stream() : 返回一个顺序流 Stream
stream = employees.stream();// default Stream
parallelStream() : 返回一个并行 (并行操作的去获取数据) Stream
parallelStream = employees.parallelStream(); }创建Stream方式二: 通过数组 //创建Stream方式二: 通过数组 @Test public void test2(){ int[] arr1 = new int[]{ 1,2,3,4,5,6,7,8,9,10};// 调用Arrays类的静态方法: static
Stream
stream(T[] array): 返回一个 IntStream stream = Arrays.stream(arr1); Employee e1 = new Employee(1001,"李小姐"); Employee e2 = new Employee(1002,"张先生"); Employee[] arr2 = new Employee[]{ e1,e2}; Stream
stream1 = Arrays.stream(arr2); } //创建Stream方式三: 通过Stream的of() @Test public void test3(){ Stream
integerStream = Stream.of(2, 3, 4, 8, 9, 6); }创建Stream方式四: 通过创建无限流 //创建Stream方式四: 通过创建无限流 @Test public void test4(){ // 迭代 public static
Stream
iterate(final T seed, final UnaryOperator
f) //遍历从前十个偶数 Stream.iterate(0,t -> t + 2).limit(10).forEach(System.out::println);// 生成 public static
Stream
generate(Supplier
s) //生成输出10个随机数 Stream.generate(Math::random).limit(10).forEach(System.out::println); }

6. 步骤二: 中间操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jj0KQ4xH-1603378957404)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223006031.png)]

筛选与切片// 1- 筛选与切片    @Test    public void test1(){           List
list = EmployeeData.getEmployees();// filter(Predicate p) --- 接受Lambda,从流中排除某些元素。 Stream
stream = list.stream(); //查询员工表中薪资大于7000的员工信息 stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println); System.out.println("==========================================================================");//分割线// limit(n) --- 截断流,使其元素不超过给定数量。 //限制输出前5个元素 list.stream().limit(5).forEach(System.out::println); System.out.println("==========================================================================");//分割线// skip(n) --- 跳过元素,返回一个扔掉了前 n 个元素的流。若流中的元素不足 n 个,则返回一个空流。与limit(n)互补。 //跳过前三个数据 list.stream().skip(3).forEach(System.out::println); System.out.println("==========================================================================");//分割线// distinct() --- 筛选,通过流所生成元素的 hashCode()和 equals() 去除重复元素 list.add(new Employee(1010,"刘强东",40,8000)); list.add(new Employee(1010,"刘强东",40,8000)); list.add(new Employee(1010,"刘强东",42,8000)); list.add(new Employee(1010,"刘强东",40,8000)); list.stream().distinct().forEach(System.out::println); }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l9WdAwat-1603378957406)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223011841.png)]

映射// 2- 映射    @Test    public void test2(){   //  map(Function f) --- 接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。        List
list = Arrays.asList("aa", "bb", "cc", "dd"); list.stream().map(str -> str.toUpperCase()).forEach(System.out::println); //练习: 获取员工姓名长度大于3的员工名字 List
employees = EmployeeData.getEmployees(); employees.stream().map(e ->e.getName()).filter( employee -> employee.length()>3).forEach(System.out::println);// flatMap(Function f) --- 接受一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。 list.stream().flatMap(StreamAPITest1::fromStringToStream).forEach(System.out::println); } public static Stream
fromStringToStream(String str){ ArrayList
list = new ArrayList<>(); for (Character c : str.toCharArray()){ list.add(c); } return list.stream(); }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fQHaOP7s-1603378957407)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223017598.png)]、

排序// 3- 排序    @Test    public void test3(){   //sorted()---自然排序        List
list = Arrays.asList(12, -54, 32, 8, 146, 21, 1); list.stream().sorted().forEach(System.out::println);//内部调用了Integer内部的自然排序 //抛异常: 原因---Employee类没有实现Comparable()// List
employeeList = EmployeeData.getEmployees();// employeeList.stream().sorted().forEach(System.out::println);//sorted(Comparator com)---定制排序 List
employeeList = EmployeeData.getEmployees(); employeeList.stream().sorted((e1,e2) -> { int compare = Integer.compare(e1.getAge(), e2.getAge()); if (compare != 0){ return compare; }else { int compare1 = Double.compare(e1.getSalary(), e2.getSalary()); return compare1; } }).forEach(System.out::println); }

7. 步骤三: 终止操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLdcWLhi-1603378957409)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223234046.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-43ErSvd9-1603378957410)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223322682.png)]

匹配与查找// 1 - 匹配与查找    @Test    public void test0(){           List
employeeList = EmployeeData.getEmployees();//allMatch(Predicate p) --- 检查是否匹配所有元素。 // 练习:是否所有的员工的年龄都大于18 boolean allMatch = employeeList.stream().allMatch(e -> e.getAge() > 18); System.out.println(allMatch);//anyMatch(Predicate p) --- 检查是否至少匹配一个元素。 // 练习:是否存在员工的工资大于10000 boolean anyMatch = employeeList.stream().anyMatch(e -> e.getSalary() > 10000); System.out.println(anyMatch);//noneMatch(Predicate p) --- 检查是否没有匹配的元素。 // 练习: 是否存在员工姓"雷" boolean noneMatch = employeeList.stream().noneMatch(e -> e.getName().startsWith("雷")); System.out.println(noneMatch);//findFirst --- 返回第一个元素 Optional
first = employeeList.stream().findFirst(); System.out.println(first);//findAny --- 返回当前流中的任意元素 Optional
any = employeeList.stream().findAny(); System.out.println(any); } @Test public void test1(){ List
employeeList = EmployeeData.getEmployees();//count --- 返回流中元素的总个数 long count = employeeList.stream().count(); System.out.println(count);//max(Comparator c) --- 返回流中最大值 // 练习: 返回最高的工资 Stream
money = employeeList.stream().map(e1 -> e1.getSalary()); Optional
maxMoney = money.max(Double::compareTo); System.out.println(maxMoney);//min(Comparator c) --- 返回流中最小值 // 练习: 返回最低工资的员工 Optional
employee = employeeList.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())); System.out.println(employee);//forEach(Consumer c) --- 内部迭代 employeeList.stream().forEach(System.out::println); //使用集合的遍历操作方法 employeeList.forEach(System.out::println); }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P4Dp0ck1-1603378957412)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223329663.png)]

归约// 2 - 归约    @Test    public void test2(){   //reduce(T identity,BinaryOperator b) --- 可以将流中元素反复结合起来,得到一个值。返回T        //练习1: 计算1-10的自然数的和        List
list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer reduce = list.stream().reduce(0, Integer::sum); System.out.println(reduce);//reduce(BinaryOperator b) --- 可以将流中元素反复结合起来,得到一个值。返回 Optional
//练习2: 计算公司所有员工工资的综合 List
employeeList = EmployeeData.getEmployees();// Optional
reduce1 = employeeList.stream().map(e1 -> e1.getSalary()).reduce(Double::sum); Optional
reduce1 = employeeList.stream().map(e1 -> e1.getSalary()).reduce((d1,d2) -> d1 + d2); System.out.println(reduce1); }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-teDxe2Wy-1603378957413)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223352830.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eK7nT6Ym-1603378957414)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223359647.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jw2G1PXX-1603378957415)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022223405699.png)]

收集// 3 - 收集    @Test    public void test3(){   //collect(Collection c) --- 将流转换为其他形式。接受一个Collector接口的实现,用于给Stream中元素做汇总的方法        //练习1: 查找工资大于6000的员工 结果返回为一个List或Set        List
employees = EmployeeData.getEmployees(); List
employeeList = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList()); employeeList.forEach(System.out::println); System.out.println(); Set
employeeSet = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet()); employeeSet.forEach(System.out::println); }

Optional类的使用

1.理解: 为了解决Java中的空指针问题而生

Optional 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表 这个值存在。

或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不 存在,

现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

2.常用方法:

创建Optional类对象的方式:- Optional.of(T t) : 创建一个 Optional 实例,t必须非空;- Optional.empty() : 创建一个空的 Optional 实例- Optional.ofNullable(T t):t可以为nul
* 通常的方法: ofNullable(T t): t可以为null*           orElse(T t): t为备胎*           get(): 如果调用对象包含值,返回该值,否则抛异常*           empty(): 创建的Optional对象内部的value = null**           get()通常与of()搭配使用。用于获取内部封装的数据value

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IyYN7sdL-1603378957416)(C:\Users\PePe\AppData\Roaming\Typora\typora-user-images\image-20201022225941830.png)]

//- Optional.of(T t) : 创建一个 Optional 实例,t必须非空;    @Test    public void test1(){           Girl girl = new Girl();//        girl = null;  //报错: NullPointerException        Optional
optional = Optional.of(girl); System.out.println(optional);// Optional[Girl{name='null'}] } //- Optional.ofNullable(T t):t可以为nul @Test public void test2(){ Girl girl = new Girl(); girl = null; Optional
optional = Optional.ofNullable(girl); System.out.println(optional);// Optional.empty }

3.典型练习:

能保证如下的方法执行中不会出现空指针的异常。

//使用Optional类实现方法优化    public String getGirlName2(Boy boy){           Optional
optionalBoy = Optional.ofNullable(boy); //此时的boy1一定非空 Boy boy1 = optionalBoy.orElse(new Boy(new Girl("花花"))); Girl girl = boy1.getGirl(); Optional
girlOptional = Optional.ofNullable(girl); //此时girl1一定非空 Girl girl1 = girlOptional.orElse(new Girl("静香")); return girl1.getName(); } @Test public void test5(){ // Girl girl = new Girl();// Boy boy = new Boy(girl);//girl是null,返回 静香 Boy boy = null;//boy是null,返回 花花 Boy boy1 = new Boy(new Girl("红红"));//正常情况,返回 红红 String s = getGirlName2(boy); System.out.println(s); }

转载地址:http://ifoq.baihongyu.com/

你可能感兴趣的文章
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>
Mysql8在Windows上离线安装时忘记root密码
查看>>
MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
查看>>
mysql8的安装与卸载
查看>>
MySQL8,体验不一样的安装方式!
查看>>
MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
查看>>
Mysql: 对换(替换)两条记录的同一个字段值
查看>>
mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
查看>>
MYSQL:基础——3N范式的表结构设计
查看>>
MYSQL:基础——触发器
查看>>