一:Lambda表达式:
1. Lambda表达式使用前后对比:
举类一:
@Test public void test(){ Runnable r1 = new Runnable() { @Override public void run() { System.out.println("我爱北京天安门!"); } }; r1.run(); System.out.println("******************************"); //lambda表达式的写法 Runnable r2=()->System.out.println("我爱北京天安门!"); r2.run(); }
举类二:
@Test public void test2(){ Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1,o2); } }; int compare = com.compare(12, 15); System.out.println(compare); System.out.println("******************************"); //lambda表达式的写法 Comparator<Integer> com2= (o1,o2)->Integer.compare(o1,o2); int compare1 = com2.compare(21, 15); System.out.println(compare1); }
2.lambda表达式的基本语法
1.举类:(o1,o2)->Integer.compare(o1,o2);
2.格式:
》lambda操作符或 箭头操作符
》左边:lambda形参列表(其实就是接口的抽象方法的形参列表)
》右边:lambda体(其实就是重写的抽象方法的方法体)
3.如何使用:分为六种情况:
//语法格式一:无参,无返回值 Runnable r1 =()-> {System.out.println("hello lambda");}; //语法格式二:一个参数,但是没有返回值 Consumer<String> con=(String str)-> {System.out.println(str);}; //语法格式三:数据类型可以省略,因为可由编译器推断出,称为“类型推断” Consumer<String> con2=(str)-> {System.out.println(str);}; //语法格式四:只有一个参数时,参数的小括号可以省略 Consumer<String> con3=str-> {System.out.println(str);}; //语法格式五:需要两个或以上参数,多条执行语句,并且可以由返回值 Comparator<Integer> com =(o1,o2)->{ System.out.println("实现函数式接口方法!"); return Integer.compare(o1,o2); }; //语法格式六:当lambda体只有一条执行语句时,return与大括号若有,都可以省略 Comparator<Integer> com2 =(o1,o2)->Integer.compare(o1,o2);
4.总结六种情况:
》左边:lambda形参列表的参数类型可以省略(类型推断):如果lambda形参列表
只一个参数,其一对()也可以省略
》右边:lambda 体应该使用一对{}包裹;如果lambda体只一条执行语句(可能是return语句,省略这一对{}和return关键字)
二:函数式接口:
1.函数式接口的使用说明
》如果一个接口中,只声明一个抽象方法,则此接口就称为函数式接口。我们可以
》在一个接口上使用@FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口。
》lambda表达式的本质:作为函数式接口的实例
2.java8中关于lambda表达式提供的4个基本的函数式接口:
具体使用:
3.总结:
3.1何时使用lambda表达式?
当需要对一个函数式接口实例化的时候,可以使用lambda表达式。
3.2 何时 使用给定的函数式接口?
如果我们开发中需要定义一个函数式接口,首先看看在已有的jdk提供的函数式接口是否提供了
能满足需求的函数式接口。如果有则直接调用即可,不需要自己再定义了。
三:方法引用:
1.理解:
方法引用可以看做式lambda表达式深层次的表达,换句话说,方法引用就是lambda表达式,
也就是函数式接口的一个实例:通过方法的名字来指向一个方法。
2.使用情境:
当要传递给lambda体的操作,已经有实现的方法了,可以使用方法引用。
3.格式:
类(或对象)::方法名
4.分为如下的三种情况:
情况1:对象::非静态方法
情况 2:类:静态方法
情况3:类:非静态方法
5.要求:
要求接口中的抽象方法的形参列表和返回值类型与方法引用的方法的形参列表和返回值类型相同!(针对情况1和情况2)
当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数时)Classname::MethodName(针对情况3)
6.使用建议:
如果给函数式接口提供实例,恰好满足方法引用的使用情景,大家可以考虑使用方法引用给函数式接口提供实例。如果不熟悉方法引用,可以使用lambda 表达式
7.使用举类:
@Test public void test4() { Consumer<String> con= s-> System.out.println(s); con.accept("北京欢迎你!"); System.out.println("****************"); PrintStream ps= System.out; //方法引用1:对象::非静态方法名 Consumer<String> con2=ps::println; con2.accept("北京欢迎你2!"); } @Test public void test5(){ Function<Double,Long> fun1 =d->Math.round(d); System.out.println(fun1.apply(14.2)); System.out.println("****************"); //方法引用2:类::静态方法名 Function<Double,Long> fun2=Math::round; System.out.println(fun2.apply(14.6)); } @Test public void test6(){ Person per =new Person(20,"tom"); Function<Person ,String> f1=p->p.getName(); System.out.println(f1.apply(per)); System.out.println("****************"); //方法引用3:类::非静态方法名 Function<Person ,String> f2=Person::getName; System.out.println(f2.apply(per)); }
四:Stream API:
1.Stream API 的理解:
》stream 关注的 是对数据的运算,与CPU打交道,集合关注的是数据的存储,与内存打交道
》java 8提供了一套api,使用这套api可以对内存中的数据进行过滤,排序,映射,归约等操作
2.注意点:
》stream 自己不会存储元素
》stream 不会改变源对象。相反,他们会返回一个持有结果的新stream
》stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
3.stream 的使用流程:
1)stream的实例化
2)一系列的中间操作(过滤,映射....)
3)终止操作
4.使用流程的注意点:
》一个中间操作链,对数据源的数据进行处理
》一旦执行终止操作,就执行中间操作链,并产生结果。之后,不会在被使用
5.stream实例化
@Test public void test7(){ //实例化方式一:调用集合的stream() List<Employee> employees = EmploeeData.ListEmployees(); Stream<Employee> stream = employees.stream(); System.out.println(stream); //实例化方式二:调用数组的静态stream() Integer[] arr= new Integer[]{1,2,3,4,5,6,7,8,9,10}; Stream<Integer> stream1 = Arrays.stream(arr); System.out.println(stream1); //实例化方式三:调用类Stream的of()方法 Stream<Integer> stream2 = Stream.of(arr); System.out.println(stream2); //实例化方式四:Stream类的迭代器和生成器 //迭代器,生成十个偶数 Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println); //生成器,生成十个随机数 Stream.generate(Math::random).limit(10).forEach(System.out::println); }
6.中间操作和终止操作
public void test8(){ //中间操作: Stream<Employee> stream = EmploeeData.ListEmployees().stream(); // filter(P):过滤器:过滤年龄大于30的员工 stream.filter(e->e.getAge()>30).forEach(System.out::println); System.out.println("*****************"); // limit(int n):显示前几条数据 EmploeeData.ListEmployees().stream().limit(3).forEach(System.out::println); System.out.println("*****************"); //skip(int n):跳过 前n条数据,显示剩余数据,如果跳过数据大于集合数据,返回空的stream EmploeeData.ListEmployees().stream().skip(4).forEach(System.out::println); System.out.println("*****************"); //map(Functional f):返回映射后的stream,并输出 EmploeeData.ListEmployees().stream().map(e->e.getName()).forEach(System.out::println); System.out.println("*****************"); //sorted():排序 Arrays.asList(1,2,8,5,-1,23,6).stream().sorted().forEach(System.out::println); //sorted(Comparator com):定制排序 EmploeeData.ListEmployees().stream().sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())).forEach(System.out::println); //终止操作: // allMatch():判断是否都符合 boolean allMatch = EmploeeData.ListEmployees().stream().limit(5).allMatch(e -> e.getAge() > 20); System.out.println(allMatch); //max():求最大值 Optional<Integer> max = EmploeeData.ListEmployees().stream().map(e -> e.getAge()).max(Integer::compareTo); System.out.println(max); //forEeach():迭代. Arrays.asList(1,2,8,5,-1,23,6).stream().forEach(System.out::println); //reduce():归约 Integer reduce = Arrays.asList(1, 2, 8, 5, -1, 23, 6).stream().sorted().reduce(0, Integer::sum); System.out.println(reduce); //collect():收集,把stream结果集转换为list或set List<String> collectList = EmploeeData.ListEmployees().stream().map(e -> e.getName()).collect(Collectors.toList()); Iterator<String> iterator = collectList.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } }
五:Optional
1.理解:为了解决java中的空指针问题而生
Optional<T>类(java.util.Optional)是一个容器类,它可以保存类的值,
代表这个值存在,或者仅仅报错null,表示这个值不存在,原来用null 表示一个值不存在,
现在Optional可以更好的表达这个概念,并且可以避免空指针
2.常用方法:
@Test public void test9(){ String str="hello"; //str=null; //1.of(T t):创建value为T类型的Optional类,且t不能为null Optional<String> op1 = Optional.of(str); //of()和get()搭配使用,获取内部封装的数据 System.out.println(op1.get()); System.out.println("******************"); //2.ofNullable(T t)创建value为T类型的Optional类,且可以为null str=null; //ofNullable()和orElse()搭配使用,获取内部封装的数据 Optional<String> op2 = Optional.ofNullable(str); //如果Op2的value为null,则str2的值为"beijing" String str2 = op2.orElse("beijing"); System.out.println(str2); }
3.典型练习:
class Boy{ private Girl girl; public Girl getGirl() { return girl; } public void setGirl(Girl girl) { this.girl = girl; } public Boy(Girl girl) { this.girl = girl; } public Boy() { } } class Girl{ private String name; public Girl(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
// Optional 之前用法 public String getGirlName(Boy boy){ if(boy!=null){ Girl girl = boy.getGirl(); if(girl!=null){ return girl.getName(); } return null; } return null; } @Test public void test10(){ String girlName = getGirlName(new Boy()); System.out.println(girlName); System.out.println(); Boy boy = new Boy(new Girl("陈德容")); String girlName1 = getGirlName(boy); System.out.println(girlName1); } // Optional 实现 public String getGirlName2(Boy boy){ Optional<Boy> boyoptional = Optional.ofNullable(boy); //boy1 一定非空 Boy boy1 = boyoptional.orElse(new Boy(new Girl("迪丽热巴"))); Girl girl = boy1.getGirl(); Optional<Girl> girl1 = Optional.ofNullable(girl); //girl2 一定非空 Girl girl2 = girl1.orElse(new Girl("古力娜扎")); String name = girl2.getName(); return name; } @Test public void test11() { Boy boy =new Boy(new Girl("lily")); boy=null; String name2 = getGirlName2(boy); System.out.println(name2); } }