Java8新特性
-
1、Lambda表达式
-
2、函数式接口
-
3、方法引用与构造器引用
-
4、Stream API
-
5、接口中的默认方法与静态方法
-
6、新时间日期API
-
7、其它新特性
一、Lambda表达式
1、jdk新增
jdk1.8接口新增:
1)、静态方法:跟随接口名使用(不能跟随对象使用)
2)、默认方法:显示通过default修饰的方法;可以在实现类中重写;需要通过实现类调用
jdk9新增:
1)、私有方法:被private关键字修饰;不能在外部类中使用;只能在接口中的默认方法中使用
2、Lambda表达式
Lambda表达式可以理解为作为实现类对象传入函数,Lambda表达式:将行为作为参数传递----> 函数式编程
如果形参 | 引用为函数式接口类型,实参 | 赋值就可以为Lambda表达式
3、Lambda语法
现在我们可以使用Lambda代替创建匿名函数的部分,Lambda的语法如下。
(形参列表)->{操作集合};
注意:Lambda表达式需要函数式接口的支持;;可以使用注解 @FunctionalInterface 修饰,可以检查是否是函数式接口。
4、FunctionInteger函数式接口
java.util.function下的函数式接口:
四大内置函数式接口:
1)、消费性接口:Consumer< T > --------void accept(T t);
happy(100000,m->System.out.println("花钱买快乐")); //消费 public static void happy(double money, Consumer<Double> con){ con.accept(money); }
2)、函数式接口:Function< T,R > -----------R apply(T t);
System.out.println(strHandler("DWIDWIIW",s->s.toLowerCase())); //对任意一个 字符串进行某种操作返回结果 public static String strHandler(String str, Function<String,String> fun){ return fun.apply(str); }
3)、断言型接口:Predicate< T > ----------boolean test(T t);
4)、供给型接口:Supplier< T > -----------T get( );
System.out.println(test(10,()->(int)Math.random()*(8-5+1)+5)); //供给型接口Supplier<T> // T get() //生成指定个数的制定规则的随机整数 public static List<Integer> test(int num, Supplier<Integer> sup){ List<Integer> list = new ArrayList<>(); for (int i = 0; i <num ; i++) { list.add(sup.get()); } return list; }
5、方法引用:
方法引用是用来简化Lambda表达式;是Lambda表达式的另外一种表现形式;
简化条件(必须满足以下2个条件):
1)当lambda体{}中的实现就是通过调用另外一个方法实现的,可以考虑是否可以通过方法引用简化
2)a)当lambda参数列表,返回值与内部引用方法的参数列表与返回值保持一致的时候 ----> 对象::成员方法 | 类名::静态方法
b)内部所引用方法的 返回值与lambda表达式的返回值一致,lambda参数列表的第一个参数作为调用内部方法的对象,lambda参数列表的第二个参数开始匹配内部引用方法参数列表 ----> 类名::成员方法
方法引用语法 :: 对象::成员方法 类名::静态方法 类名::成员方法 List<Integer> list=List.of(2,3,4,5,6,7); list.forEach(System.out::println); Map<String,Integer> map= Map.of("aaa",2,"hhh",4); map.forEach((k,v)->System.out.println(k+"----"+v)); BiFunction<Double,Double,Double> fun = Math::max; System.out.println(fun.apply(1.4,8.2)); BiPredicate<String,String> bi = String::equals; System.out.println(bi.test("你你你你",new String("你你你你")));
二、Stream流 API
1、Stream
I O 流 : 关注数据的传输
集合|数组 : 关注数据的存储
Stream流 : 关注数据的运算;将由数据源产生的元素序列进行流式运算
2、使用步骤 :
1)获取创建Stream流
2)一些列流式中间操作
3)终止行为
3、Stream特点 :
1)Stream本身不存储数据
2)Stream的运算不影响数据源
3)所有中间操作都返回持有结果的新的流
4)流是一次性的流,一旦已经使用就被破坏,无法重复使用多次
5)延迟执行|惰性加载 : 当获取终止行为的时候所有的中间操作才会执行
4、获取Stream的方式 :
1)Collection-->stream() 集合转流
2)Arrays.stream() 数组转流
3)Stream.of(...) 直接转流
//Collection-->stream() List<Integer> list =List.of(1,2,3,4,5); Stream<Integer> s1=list.stream(); s1.forEach(System.out::println); //Arrays.stream() String[] arr={"apple","banana","orange","pear","peach"}; Stream<String> s2= Arrays.stream(arr); s2.forEach(System.out::println); //s2.forEach(System.out::println);遍历一次就破坏了 //Stream.of() Stream<Integer> s3=Stream.of(5,4,6,2,3); s3.forEach(System.out::println);
(一)Stream中间操作 :
1、过滤
<T> filter(Predicate<? super T> predicate) 返回由与给定谓词匹配的此流的元素组成的流。
2、截取
Stream<T> limit(long maxSize) 返回由该流的元素组成的流,长度被截断为不超过maxSize 。
3、跳过
Stream<T> skip(long n) 在丢弃流的前n元素后,返回由该流的剩余元素组成的流。
4、去重
Stream<T> distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流。
根据equals与hashCode方法,需要根据内容重写
5、排序
Stream<T> sorted() 返回由该流的元素组成的流,按自然顺序排序。
Stream<T> sorted(Comparator<? super T> comparator) 返回由该流的元素组成的流,根据提供的Comparator排序。
public class Class002_Stream { static List<Employee> emps = Arrays.asList( new Employee(103,"迪丽热巴",30,8888), new Employee(101,"古力娜扎",28,7777), new Employee(102,"易烊千玺",23,8888), new Employee(105,"哈妮克孜",25,6666), new Employee(105,"哈妮克孜",25,6666), new Employee(104,"欧娜娜娜",28,7777) ); public static void main(String[] args) { emps.stream() .filter(e->e.getAge()<30)//过滤 .limit(4)//截取 .skip(1)//丢弃n前面的元素 .distinct()//去重 .sorted((x,y)->Integer.compare(x.getAge(),y.getAge()))//排序 .forEach(System.out::println);//遍历 } }
6、映射
将流操作的每一个元素映射成为另外一种结果 | 提取信息
1)map : 将参数函数应用与此流的所有元素 ,映射成为不同的结果,最后返回持有所有结果的新的流
<R> Stream<R> map(Function<? super T,? extends R> mapper) 返回由将给定函数应用于此流的元素的结果组成的流。
2)flatMap :
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
返回一个流,其中包含将此流的每个元素替换为通过将提供的映射函数应用于每个元素而生成的映射流的内容的结果。
3)map与flatMap :
a.映射结果类型的要求不同
map : 映射结果没有类型要求,可以为任意类型,包括私有
flatMap : 映射的结果必须为一个流,不能为其他类型
b.映射结果返回流的结构不同
map : 返回持有所有映射结果的新的流 ,如果映射结果为一个流,最终返回的Stream< Stream >
flatMap :在返回之前先对所有映射结果流进行连接,连接成为一个流返回、
public class Stream_2 { static List<Employee> emps = Arrays.asList( new Employee(103,"迪丽热巴",30,8888), new Employee(101,"古力娜扎",28,7777), new Employee(102,"易烊千玺",23,8888), new Employee(105,"哈妮克孜",25,6666), new Employee(105,"哈妮克孜",25,6666), new Employee(104,"欧娜娜娜",28,7777) ); public static void main(String[] args) { //map //获取员工的姓名,将员工集合转成流--->去重---->map映射----->遍历输出 emps.stream() .distinct() //.map(e->e.getName()) .map(Employee::getName)//输出结果为String类型 .forEach(System.out::println); //统计所有的字符串中的个数 Stream<String> s= Stream.of("aaaaa","222333","99i"); //s.map(str->str.length()) s.map(String::length).sorted().forEach(System.out::println); //提取所有员工的薪资降序排序 emps.stream() //获取每个员工的薪资 .map(Employee::getSal) //对得到的流进行降序排序 .sorted((x,y)->Double.compare(y,x)) .forEach(System.out::println); //flapMap emps.stream() .distinct() .flatMap(e->Stream.of(e.getName()))//输出的为流 .forEach(System.out::println); //map emps.stream() //去重 .distinct() //map映射,将得到的员工姓名转成Stream流, .map(e->Stream.of(e.getName())) //外边遍历流里的每一个流。里边遍历每一个内部流的数据 .forEach(st->{st.forEach(System.out::println);}); } }
(二)终止行为
1、遍历
void forEach(Consumer<? super T> action) 对此流的每个元素执行一个操作。
2、查找
Optional<T> findAny() 返回描述流的某些元素的Optional ,如果流为空,则返回空的Optional 。
Optional<T> findFirst() 返回描述此流的第一个元素的Optional ,如果流为空,则返回空的Optional 。
3、匹配
boolean noneMatch(Predicate<? super T> predicate) 返回此流的任何元素是否与提供的谓词匹配。
boolean allMatch(Predicate<? super T> predicate) 返回此流的所有元素是否与提供的谓词匹配。
boolean anyMatch(Predicate<? super T> predicate) 返回此流的任何元素是否与提供的谓词匹配。
public class Stream_3 { static List<Employee> emps = Arrays.asList( new Employee(103,"迪丽热巴",30,9888), new Employee(101,"古力娜扎",28,7777), new Employee(102,"易烊千玺",23,8888), new Employee(105,"哈妮克孜",25,6666), new Employee(105,"哈妮克孜",25,6666), new Employee(104,"欧娜娜娜",28,7777) ); public static void main(String[] args) { //找到员工薪资最高的员工信息 Optional<Employee> op1=emps.stream() .distinct() .sorted((x,y)->Double.compare(y.getSal(),x.getSal())) .findFirst(); //boolean isEmpty() //如果值不存在,则返回true ,否则返回false 。 //boolean isPresent() //如果存在值,则返回true ,否则返回false 。 if (op1.isPresent()){ //T get() //如果存在值,则返回该值,否则抛出NoSuchElementException 。 System.out.println(op1.get()); } //找到某一个元素 System.out.println( emps.parallelStream() .distinct() .findAny() ); //找到所有员工年龄>18岁的 System.out.println( emps.stream() .distinct() //如果存在就输出true,get()是提取一个元素 .allMatch(e->e.getAge()>=18) ); } }
4、统计
long count ( ) 返回此流中元素的计数。
Optional<T> max ( Comparator<? super T> comparator) 根据提供的Comparator返回此流的最大元素。
Optional<T> min ( Comparator<? super T> comparator) 根据提供的Comparator返回此流的最小元素。
5、规约
Optional<T> reduce(BinaryOperator<T> accumulator) 使用associative累积函数对此流的元素执行reduction ,并返回Optional描述减少的值(如果有)。
T reduce(T identity, BinaryOperator<T> accumulator) 使用提供的标识值和associative累积函数对此流的元素执行reduction ,并返回减少的值。
注意 :map-->reduce 先提取后运算。
6、收集
collect ,收集,可以说是内容最繁多、功能最丰富的部分了。
从字面上去理解,就是把一个流收集起来,最终可以是收集成一个值也可以收集成一个新的集合。
collect 主要依赖 java.util.stream.Collectors 类内置的静态方法。
<R, A> R collect(Collector<? super T,A,R> collector) 使用Collector对此流的元素执行mutable reduction操作。
public class Stream_5 { static List<Employee> emps = Arrays.asList( new Employee(103,"迪丽热巴",30,9888), new Employee(101,"古力娜扎",28,7777), new Employee(102,"易烊千玺",23,9999), new Employee(105,"哈妮克孜",25,6666), new Employee(105,"哈妮克孜",25,6666), new Employee(104,"欧娜娜娜",28,7777) ); public static void main(String[] args) { //统计所有员工的总数 System.out.println( emps.stream() .distinct() .count() ); //找到薪资最高的员工 System.out.println( emps.stream() .distinct() .max((x,y)->Double.compare(x.getSal(),y.getSal())) .get() ); //计算1+2+3+4+5+6 System.out.println( Stream.of(1,2,3,4,5,6) //.reduce((x,y)->x+y) .reduce((x,y)->{ System.out.println(x+"\t+"+y+"\t="+(x+y)); return x+y; }) .get() ); //计算每月员工的薪资总和 System.out.println( emps.stream() .distinct() .map(Employee::getSal) .reduce((x,y)->x+y) ); } }