Java补充(Java8新特性)(和IO都很核心)
1.1、为什么使用Lambda表达式 Lambda表达式起步案例
下面源码注释是传统写法,代码是简写表达式写法
import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.function.Consumer; /** 学什么?* 1、Lambda表达式* 2、Stream API* 3、Optional类 NullPointerException* 目前存在的问题?* 方法不能作为参数传递* 如何解决这个问题?* 行为参数化* */public class MyTest02 { public static void main(String[] args) { //匿名内部类 /*Thread th1 = new Thread(new Runnable() { @Override public void run() { System.out.println("hello Java8"); } }); th1.start();*/ Thread th1 = new Thread(() -> { System.out.println("hello Java8"); }); th1.start(); ArrayList list = new ArrayList(); list.add("111111"); list.add("11"); list.add("11222"); list.add("1"); /*Collections.sort(list, new Comparator() { @Override public int compare(String o1, String o2) { //return o1.length() - o2.length(); return Integer.compare(o1.length(), o2.length()); } });*/ // -> 后省略了大括号和return 还有o1,o2的String Collections.sort(list, (o1,o2) -> Integer.compare(o1.length(), o2.length())); System.out.println(list); /*list.forEach(new Consumer() { @Override public void accept(String s) {//s -- 每次被遍历到的元素 System.out.println(s); } }); 下面是简写后的*/ list.forEach(s -> System.out.println(s)); list.forEach(System.out::println); }}
1.2、Lambda表达式写法
Lambda表达式是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格。使Java的语言表达能力得到了提升。
语法:
Lambda表达式操作符或箭头操作符:->
左侧:指定了Lambda表达式需要的参数列表(其实就是接口中的抽象方法的形参列表)
右侧:指定了Lambda体,是抽象方法的实现逻辑,也即Lambda表达式要执行的功能(其实就是重写的抽象方法的方法体)。
先把匿名内部类的对象找出来,再看方法参数和方法体
即源码
package day33; import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.function.Consumer; /** 学什么?* 1、Lambda表达式* 2、Stream API* 3、Optional类 NullPointerException* 目前存在的问题?* 方法不能作为参数传递* 如何解决这个问题?* 行为参数化* Lambda表达式* -> Lambda操作符或箭头操作符* 左侧:方法的参数列表* 右侧:方法的方法体* 方法:重写的方法* Lambda表达式简写/进阶写法* 1、如果参数列表没有参数,要写成()* 2、如果参数列表有参数* 参数个数>=2 (数据类型1 参数名1,数据类型2 参数名2,数据类型3 参数名3)* 参数个数>=2 (参数名1, 参数名2,参数名3) !!!!!* 只有一个参数 (数据类型 参数名)* 只有一个参数 (参数名)* 只有一个参数 参数名 !!!!!* 3、右侧 - 如果方法体有多行代码,必需写{}* 4、右侧 - 如果方法体只有一行代码,不用写{},不用写return,不用写结尾的";" * */public class MyTest02 { public static void main(String[] args) { //匿名内部类 /*Thread th1 = new Thread(new Runnable() { @Override public void run() { System.out.println("hello Java8"); } }); th1.start();*/ Thread th1 = new Thread(() -> { System.out.println("hello Java8"); }); th1.start(); ArrayList list = new ArrayList(); list.add("111111"); list.add("11"); list.add("11222"); list.add("1"); /*Collections.sort(list, new Comparator() { @Override public int compare(String o1, String o2) { //return o1.length() - o2.length(); return Integer.compare(o1.length(), o2.length()); } });*/ // -> 后省略了大括号和return 还有o1,o2的String Collections.sort(list, (o1,o2) -> Integer.compare(o1.length(), o2.length())); System.out.println(list); /*list.forEach(new Consumer() { @Override public void accept(String s) {//s -- 每次被遍历到的元素 System.out.println(s); } }); 下面是简写后的*/ list.forEach(s -> System.out.println(s)); list.forEach(System.out::println); }}
1.3、函数式接口_@Functional注解
@FunctionalInterface
@Override
作用:编译器帮我们检查标注了该注解的接口是不是函数式接口
|-- 是 -- 编译通过
|-- 不是 -- 无法编译通过
注意:该注解的作用只是检查的作用,可以不写
相关源码显示:
package day33; public class MyTest03 { public static void aaa(MyInterface a, int m , int n) { a.test(m,n); } public static void main(String[] args) { /*aaa(new MyInterface() { @Override public void test(int a, int b) { System.out.println(a + ":" + b); } },1,2);*/ aaa((a,b) -> System.out.println(a + ":" + b),1,2); }}
package day33; @FunctionalInterfacepublic interface MyInterface { void test(int a , int b); //唯一的一个抽象方法}
———————自己定义的,Java官方也有
1.4、函数式接口_常见函数式接口说明
1.5、复合的Lambda表达式
比较器复合 和 谓词复合
package day34; import java.util.ArrayList;import java.util.Comparator;import java.util.function.Predicate; //比较器复合public class MyTest02 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add(new Apple(150,"red")); list.add(new Apple(210,"red")); list.add(new Apple(300,"yellow")); list.add(new Apple(90,"green")); list.add(new Apple(90,"yellow")); list.add(new Apple(100,"green")); list.add(new Apple(123,"red")); //按照重量降序排序 //list.sort(Comparator.comparing(Apple::getWeight).reversed()); //按照重量降序排序,如果重量相同那就按照颜色的升序排序 /*list.sort(Comparator. comparing(Apple::getWeight) .reversed() .thenComparing(Apple::getColor));*/ //.thenCompareing(Comparator.comparing(Apple::getColor).reversed())); //list.removeIf(item -> item.getWeight() == 90); //删除颜色不是红颜色的苹果 Predicate的复合即谓词复合 Predicate redApple = item -> item.getColor().equals("red"); //list.removeIf(redApple.negate()); //去除红颜色并且重量大于150的苹果 list.removeIf(redApple.and(item -> item.getWeight() > 150)); //去除红色并且重量大于150的苹果或绿苹果 list.removeIf(redApple.and(item -> item.getWeight() > 150).or(item -> item.getColor().equals("green"))); list.forEach(System.out::println); }}
二、方法引用
1、本质:就是Lambda表达式,对Lambda表达式的简写
2、比如类名::方法名,一般带两个冒号的就是
什么情况下Lambda表达式可以改成方法引用?
1)Lambda表达式的方法体只有一行代码,并且只调用了一个方法
2)除了参数列表和1)中的"一个方法",没有再引入其他的额外的内容
三、Stream_中间操作
3.1、filter 过滤符合条件的
package day34; import java.util.ArrayList; public class MyTest04 { public static void main(String[] args) { //filter -- 中间操作 ArrayList list = new ArrayList<>(); list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); //在控制台打印长度大于2的字符串 list.stream() .filter(item -> item.length() > 2) //--> Stream .forEach(System.out::println); System.out.println("--------------------------------"); System.out.println(list); }}
3.2、distinct 去重
import java.util.ArrayList; public class MyTest04 { public static void main(String[] args) { //filter -- 中间操作 ArrayList list = new ArrayList<>(); list.add("Aqaa"); list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); //在控制台打印长度大于2的字符串 /*list.stream() .filter(item -> item.length() > 2) //--> Stream .forEach(System.out::println); System.out.println("--------------------------------");*/ //去除重复 list.stream() .distinct() //根据元素的equals和hashCode方法判断是否重复 .forEach(System.out::println); System.out.println("--------------------------------"); ArrayList list1 = new ArrayList<>(); list1.add(new Apple(150,"red")); list1.add(new Apple(210,"red")); list1.add(new Apple(300,"yellow")); list1.add(new Apple(90,"green")); list1.add(new Apple(90,"yellow")); list1.add(new Apple(90,"yellow")); list1.add(new Apple(100,"green")); list1.add(new Apple(123,"red")); list1.stream() .distinct() .forEach(System.out::println); }}
3.3、limit 截断流 使其元素不超过给定数量
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); list1.stream() .limit(3) .forEach(System.out::println);
3.4、skip 跳过元素,返回一个扔掉了前n个元素的流,若元素不足n个,返回空流
list1.stream() .skip(3) .forEach(System.out::println);
3.5、map 映射 将流中的每个元素进行转换
3.5.1、传统做法
package day34; import java.util.ArrayList;import java.util.LinkedHashSet; public class MyTest05 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); //map - 映射 - 将流中的每个元素进行转换 //获取list中每个字符串的长度并在控制台打印 list.stream()//String .map(s -> s.length())//长度 .forEach(System.out::println); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); //获取list中每个字符串的长度并在控制台打印,去除重复的长度 list.stream() .map(String::length) .distinct() .forEach(System.out::println); System.out.println(" setLength = new LinkedHashSet<>(); for (String s : list) { setLength.add(s.length()); } for (Integer len : setLength) { System.out.println(len); } }}
3.5.2、flatMap 把多个流合并成一个流
System.out.println("__________________________________________"); list.stream() .mapToInt(String::length) .distinct() .forEach(System.out::println); ArrayList list1 = new ArrayList<>(); list1.add("Hello"); list1.add("World"); //H e l l o W o r l d list1.stream() //String .map(s -> s.split("")) //String --> String[] .flatMap(arr -> Arrays.stream(arr)) //String[] --> Stream -->Stream合并 .forEach(System.out::println); /* 传统的 上面的是新的 String[] arr = "hahaha".split(""); System.out.println(Arrays.toString(arr));*/
四、Stream_终端操作
补forEach:没有返回值
4.1、allMatch_anyMatch_noneMatch
package day34; import java.util.ArrayList; public class MyTest06 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); //list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); boolean flag = list.stream() .allMatch(s -> s.length() > 2); //判断所有元素是否达到要求 System.out.println(flag); boolean flag1 = list.stream() .anyMatch(s -> s.length() > 2); //判断是否有元素是否达到要求 System.out.println(flag1); boolean flag2 = list.stream() .noneMatch(s -> s.length() > 2); //判断没有任何元素达到要求 System.out.println(flag2); }}
4.2、findFirst_findAny
package day34; import java.util.ArrayList;import java.util.Optional; public class MyTest06 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); //list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); boolean flag = list.stream() .allMatch(s -> s.length() > 2); //判断所有元素是否达到要求 System.out.println(flag); boolean flag1 = list.stream() .anyMatch(s -> s.length() > 2); //判断是否有元素是否达到要求 System.out.println(flag1); boolean flag2 = list.stream() .noneMatch(s -> s.length() > 2); //判断没有任何元素达到要求 System.out.println(flag2); Optional first = list.stream().findFirst(); //获取第一个元素 System.out.println(first.get()); Optional any = list.stream().findAny(); //获取任意一个元素 System.out.println(any.get()); }}
4.3、reduce
!!!!!归约!!!!!
之前见到过的终端操作都是返回一个boolean(allMatch之类的)、void(forEach)或Optional对象(findAny)等。使用reduce操作来表达更复杂的查询,此类查询需要将流中所有元素反复结合起来,得到一个值,比如一个Integer.这样的查询可以被归类为归约操作(将流归约成一个值)
package day34; import java.util.Arrays;import java.util.Optional; public class MyTest07 { public static void main(String[] args) { Integer[] arr = new Integer[]{1,2,3}; /*Integer sum = Arrays.stream(arr) .reduce(0, (n1, n2) -> n1 + n2);*/ /*Integer sum = Arrays.stream(arr) .reduce(0, (n1, n2) -> Integer.sum(n1, n2));*/ Integer sum = Arrays.stream(arr) .reduce(0, Integer::sum); System.out.println(sum); System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"); Optional sum1 = Arrays.stream(arr) .reduce(Integer::sum); System.out.println(sum1.get()); //最大值 /*Integer max = Arrays.stream(arr) .reduce(arr[0], (n1, n2) -> { if (n1 > n2) { return n1; } else { return n2; } });*/ /* Integer max = Arrays.stream(arr) .reduce(arr[0], (n1, n2) -> n1 > n2 ? n1 : n2);*/ /*Integer max = Arrays.stream(arr) .reduce(arr[0], (n1, n2) -> Integer.max(n1, n2));*/ Integer max = Arrays.stream(arr) .reduce(arr[0], Integer::max); System.out.println("Max = " + max); Optional max1 = Arrays.stream(arr) .reduce(Integer::max);//没有起始值的 System.out.println("Max1 = " + max1.get()); //最小值 Integer min = Arrays.stream(arr) .reduce(arr[0], Integer::min); System.out.println("Min = " + min); //最佳实践:包装类判断值是否相同要使用equals判断 Integer i1 = 1000; Integer i2 = 1000; System.out.println(i1 == i2);//不行 System.out.println(i1.equals(i2)); }}
小练习:
怎样用map 和 reduce 方法计算流中元素的数据。
//计算流中的元素个数 //把元素值都变成1,累加起来即为sum Integer count = Arrays.stream(arr) .map(item -> 1) .reduce(0, Integer::sum); System.out.println(count);
4.4、sorted
package day34; import java.util.ArrayList;import java.util.Comparator; public class MyTest08 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); //list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); list.stream() .sorted() //自然排序 .forEach(System.out::println); System.out.println("=============================================="); /*list.stream() .sorted((s1, s2) -> Integer.compare(s1.length(), s2.length())) .forEach(System.out::println);*/ list.stream() .sorted(Comparator.comparingInt(String::length).reversed().thenComparing(String::compareTo)) .forEach(System.out::println); System.out.println("-----------------------------------------------"); System.out.println(list.stream().count()); }}
4.5、Stream的终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值。例如:List、Integer,甚至是void。
流进行了终止操作后,不能再次使用。
package day35; import java.util.ArrayList;import java.util.stream.Stream; public class MyTest01 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); Stream stream = list.stream(); stream.map(item -> 1).forEach(System.out::println); //流一旦进行了终端操作就不能再重复使用,报错 stream.map(item -> 1).forEach(System.out::println); }}
4.5.1、匹配与查找
package day35; import java.util.ArrayList;import java.util.Optional;import java.util.stream.Stream; public class MyTest01 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); System.out.println(list.stream().count()); Optional max = list.stream() //.max((s1, s2) -> s1.compareTo(s2)); .max(String::compareTo); System.out.println(max.get()); }}
4.6、collect
package day35; import java.util.*;import java.util.stream.Collectors; public class MyTest02 { public static void main(String[] args) { ArrayList list = new ArrayList<>(); list.add("Aqaa"); list.add("Bssss"); list.add("Cwww"); list.add("Ddsdd"); list.add("Edadc"); /*ArrayList nums = new ArrayList<>(); list.stream() .map(String::length) .forEach(len -> nums.add(len)); System.out.println(nums);*/ List nums = list.stream() .map(String::length) .collect(Collectors.toList());//把流当中的元素给搜集到集合里面,并作为元素返回 Set nums1 = list.stream() .map(String::length) .collect(Collectors.toSet());//Set方法自动去重,Collectors可省略 TreeSet num2 = new TreeSet<>(nums1);//合并转换 System.out.println(num2); System.out.println(nums1); System.out.println("------------------------------------------------"); String s = list.stream() .map(str -> str.substring(0, 1)) .collect(Collectors.joining("+")); System.out.println(s); //例子:搜集所有参与交易的交易员姓名到一个集合中 /*List names = transactions.stream() .map(Transaction::getTrader) .map(Trader::getName) .distinct .collect(Collectors.toList()); System.out.println(names);*/ }}