本文共 17165 字,大约阅读时间需要 57 分钟。
@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(){ //之前的写法 Comparatorcom1 = 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);}
* 1.举例: (o1,o2) -> Integer.compare(o1,o2);* 2.格式:* -> :lambda操作符 或 箭头操作符* ->的左边: lambda形参列表 (其实就是接口中的抽象方法的形参列表)* ->的右边: lambda体 (其实就是重写的抽象方法的方法体)
* ->左边: lambda形参列表可以省略(类型推断);* 如果参数列表没有参数,则保留小括号: (s) ->* 如果参数列表只有一个参数,其一对小括号也可省略: s ->* 如果参数列表有两个或两个以上的参数,则保留小括号和多个参数: (o1,o2,...) ->* ->右边: lambda体应该使用一对{}包裹;* 如果lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return关键字
.
* 如果一个接口中,只声明了一个抽象方法,则此接口就成为函数式接口* 我们可以在一个接口上使用@FunctionalInterface注解,这样做可以检验它是否是一个函数式接口。* 所以以前用匿名实现类表示的现在都可以用Lambda表达式 * Lambda表达式的本质: 作为接口的实例 * 一个接口仅有一个待实现方法
当需要对一个函数式接口实例化的时候,可以使用Lambda表达式。
如果我们开发中需要定义一个函数式接口,
首先看看在已有的jdk提供的函数式接口是否提供了能满足需求的函数式接口。
如果有,则直接调用即可。不需要自己再自定义
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就 是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向 一个方法。
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
使用的格式: 类(或对象) :: 方法名
* 情况1) 对象 :: 非静态方法(实例方法)* 情况2) 类 :: 静态方法** 情况3) 类 :: 非静态方法
要求接口中的抽象方法的形参列表和返回值类型 与 方法引用的方法的形参列表和返回值类型 相同(针对于情况1与情况2)当函数式接口方法的第一个参数是需要引用方法的调用者,并且第二个参数是需要引用方法的参数(或无参数)时:ClassName::methodName
如果给函数式接口提供实例,恰好满足方法引用的使用情景,大家就可以考虑方法引用给函数式接口提供实例。
如果大家不熟悉方法引用,那么还可以使用Lambda表达。
public class MethodRefTest { // 情况1:对象 :: 实例方法 //Consumer中的void accept(T t) //PrintStream中的void println(T t) @Test public void test1() { //Lambda表达式写法 Consumercon1 = 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))); }}
类名 :: new
* 和方法引用类似,函数式接口的抽象方法的形参列表和构造器的形参列表一致。* 抽象方法的返回值类型即为构造器所属的类的类型
//原始写法 Suppliersup0 = 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); }
数组类型[] :: new
//数组引用 //Function中的R apply(T t) @Test public void test4(){ //Lambda表达式写法 Functionfunc1 = 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关注的是对数据的运算,与CPU打交道* 集合关注的是数据的存储,与内存打交道** Java8提供了一套api,使用这套api可以对内存中的数据进行过滤、排序、映射、归约等操作。类似于sql对数据库表的操作
* Stream 自己不会储存元素。* Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。* Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
* ① Stream的实例化* ② 一系列的中间操作(过滤、映射、...)* ③ 终止操作
* ①一个中间操作链,对数据源的数据进行处理* ②一旦执行终止操作,就执行中间操作链,并产生结果。之后,此Stream不能再被使用
创建Stream的四种方式创建Stream方式一: 通过集合 //创建Stream方式一: 通过集合 @Test public void test1(){ Listemployees = 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); }
筛选与切片// 1- 筛选与切片 @Test public void test1(){ Listlist = 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); }
映射// 2- 映射 @Test public void test2(){ // map(Function f) --- 接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 Listlist = 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(); }
排序// 3- 排序 @Test public void test3(){ //sorted()---自然排序 Listlist = 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); }
匹配与查找// 1 - 匹配与查找 @Test public void test0(){ ListemployeeList = 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); }
归约// 2 - 归约 @Test public void test2(){ //reduce(T identity,BinaryOperator b) --- 可以将流中元素反复结合起来,得到一个值。返回T //练习1: 计算1-10的自然数的和 Listlist = 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); }
收集// 3 - 收集 @Test public void test3(){ //collect(Collection c) --- 将流转换为其他形式。接受一个Collector接口的实现,用于给Stream中元素做汇总的方法 //练习1: 查找工资大于6000的员工 结果返回为一个List或Set Listemployees = 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 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表 这个值存在。
或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不 存在,
现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
创建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
//- Optional.of(T t) : 创建一个 Optional 实例,t必须非空; @Test public void test1(){ Girl girl = new Girl();// girl = null; //报错: NullPointerException Optionaloptional = 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 }
能保证如下的方法执行中不会出现空指针的异常。
//使用Optional类实现方法优化 public String getGirlName2(Boy boy){ OptionaloptionalBoy = 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/