-
javaSE高级篇5 — java8新特性详解———更新完毕
java8新特性
在前面已经见过一些东西了,但是:挖得有坑儿
1、lambda表达式
- lambda表达式是jdk1.8引入的全新语法特性
-
它支持的是:只有单个抽象方法的函数式接口。什么意思?
- 就是说:这个接口下面只有一个抽象方法是真正属于自己的( 像那种从Object类里面继承过来的不算 ———— 所以这样严格来讲:这个接口里面就只有一个抽象方法是真正属于自己的 )
-
什么时候会用这个东西? ———— 总的一句话是:传参的时候是一个函数式接口就会用( 这句话包含了很多东西,这里不理解没事儿,学完了就懂了 )
- 1、简化匿名内部类 ( 学完这个lambda表达式之后,回过来采用 1、接口 ——> 实现类( new实现类对象,调接口中的方法 )、2、把接口的实现类弄成内部类( 成员、局部、匿名 )、3、弄成lambda表达式的样子,这样一步一步简化,推导出lambd表达式,最后一对比就突然发现lambda表达式好简单了( 注意:接口中那个抽象方法是单个参数、多个参数( lambda加不加()小括号 )、无返回值、有返回值( lambda写不写返回值类型 )、业务代码为一句、多句( lambda要不要加花括号{} 的情况 ) ) ———— 这句话很重要,记住这句话,然后弄完我后面说的这些之后,再回过来实践一下我说的这句话,会收获很多,只要把这句话搞懂了,lambda表达式就彻底懂了
-
-
以前玩儿匿名内部类的时候不是弄过一点吗,回顾一下
-
package cn.xieGongZi.reviewInnerClass; import java.util.TreeSet; // 回顾一下以前玩匿名内部类 public class Demo { public static void main(String[] args) { // 以前在treeSet中研究过它的底层排序原理,所以再来玩儿一下 TreeSet<Integer> treeSet = new TreeSet<>(); treeSet.add(20); treeSet.add(30); treeSet.add(1); treeSet.add(9); treeSet.add(10); treeSet.add(18); System.out.println( treeSet ); // 这是升序排列,那我想降序排列呢? } }
来嘛:改变排序规则
-
package cn.xieGongZi.reviewInnerClass; import java.util.Comparator; import java.util.TreeSet; // 回顾一下以前玩的匿名内部类 public class Demo { public static void main( String[] args ) { // 来吧:改变排序规则 ———— 重写comparator接口( 匿名内部类 ) TreeSet<Integer> treeSet = new TreeSet<>( new Comparator<Integer>() { @Override public int compare( Integer o1, Integer o2 ) { // 注意观察这里 ( 这就是传递的参数、及参数个数 ) // 记得用这个写法 和 lambda需要传参时的写法作对比 return o2 - o1; // 改变比较规则 } }); treeSet.add(20); treeSet.add(30); treeSet.add(1); treeSet.add(9); treeSet.add(10); treeSet.add(18); System.out.println( treeSet ); } }
这样虽然是把排序规则改变了,但是不麻烦吗?
-
所以:lambda表达式来了————再来回顾一下lambda的表达式是怎么样的?
-
【对象名】 ( 参数 )-> { 集合体( 业务代码 )} ———— 那再来玩儿一下
-
package cn.xieGongZi.reviewInnerClass; import java.util.TreeSet; public class UseLambda { public static void main(String[] args) { // 来吧:改变排序规则 ———— 使用lambda表达式 TreeSet<Integer> treeSet = new TreeSet<>( ( o1,o2 )-> { /* 1、为什么这里写两个o1,o2的参数,然后加个{} 这个表达式就可以去执行相应的东西 即:这个表达式怎么知道:老衲重写的是Comparator接口? 2、另外一个问题:看起来这个o1,o2貌似没有值吧 它不是参数吗,在这里看起来没赋值啊,所以最后怎么可以得出想要的结果? */ return o2 - o1; // 改变比较规则————即:业务代码 } ); // 记得用这里的写法 和 前面匿名内部类那里的写法作对比 ———— 会发现lambda表达式如此的简单 // 记得尝试模拟一个参数、多个参数、有返回值、无返回值的写法 ( 当然:不是用这个、而是自己设计 ) treeSet.add(20); treeSet.add(30); treeSet.add(1); treeSet.add(9); treeSet.add(10); treeSet.add(18); System.out.println(treeSet); } }
-
为了解决解决上述代码中的两个问题,来看一下如下代码( 顺便引申出函数式接口是什么意思 )
-
package cn.xieGongZi.functionInterface; public class Test { public static void main(String[] args) { // 开始玩儿 test test = new test(); test.doAdd( new TestFunctionInterface() { /* 这中间的这一堆就是一个对象嘛 ———— 一个TestFunctionInterface对象 这里面是用了这个对象 去 调用了TestFunctionInterface中的add()方法 所以结果来了:lambda表达式中有一个对象名,这个对象名就是这里的TestFunctionInterface对象 传递的参数有没有值:有,为什么? 就是调用doAdd()方法的时候不得需要一个TestFunctionInterface对象吗,虽然使用lambda可以不用对象名 但是:参数是必写的 ( 因为add( int a ) 需要一个int类型的a ,如果add()没有参数就可以不写 ) 然后这个对象就把这个参数a携带进去了,那这个对象把参数携带去了哪里? 把这个值赋给了重写的add( int a )方法里面需要的这个int a参数了嘛 因此:总结一句话就是lambda表达式就是指: 把一段代码( 如:t.add( int a ) —— 这里面可能需要携带参数,也可能不需要、甚至可能是一个、多个 需不需要携带参数,看那个接口中的抽象方法需不需要 ) 传递给了某一个函数 最后让这个函数( 就是lambda做的事情 )去执行相关的操作( 这个操作是怎么样的,就是自己写的业务代码 ) 要真正理解lambda表达式,关键就是这里的回调,就这里会绕一下 */ @Override public void add( int a ) { // 正常是这么玩儿的————重写这个方法 System.out.println("老衲自东土大唐而来....." + a ); } }); /* 这里面doAdd()中是不是需要传一个TestFunctionInterface对象 这个对象指向的那个类型,就是他喵说的函数式接口( 这个接口只有一个真正属于自己的抽象方法 ) 在java中是不是函数式接口,会有一个注解来进行说明@FunctionalInterface 这个就是一个声明性的东西而已 就相当于是给这个接口做了一个标记,标记它是一个函数式接口 */ } } // 定义一个接口 interface TestFunctionInterface{ // 这里面只有这一个方法是真正属于这个接口的 void add( int a ); } class test{ public void doAdd( TestFunctionInterface t ){ /* 这个t就相当于是我们使用lambda时的那个对象名( 用lambda时可写可不写,看情况来做 ) */ t.add( int a ); // t.add()就相当于是lambda做的事情 // 这里用TestFunctionInterface对象t 回调了 TestFunctionInterface中的抽象方法 } }
-
-
-
【对象名】 ( 参数 )-> { 集合体( 业务代码 )} ———— 那再来玩儿一下
-
所以:lambda表达式来了————再来回顾一下lambda的表达式是怎么样的?
-
-
以前玩儿匿名内部类的时候不是弄过一点吗,回顾一下
-
-
再继续研究:函数式接口有哪些类型( 即:分为哪几种 )
-
1、消费型( Consumer) ——— 又懵逼,这是啥子鬼玩意儿? ———— 看源码涩
-
把源码提取出来分析一下
-
@FunctionalInterface public interface Consumer<T> { void accept(T t); // default Consumer<T> andThen(Consumer<? super T> after) { // 看不懂这里的话,那这一段先不看,这样是不是就很明白了 // Objects.requireNonNull(after); // 这他喵的这接口里面不就只有accept()这一个抽象方法吗 // return (T t) -> { accept(t); after.accept(t); }; // 这个单词已经在网络编程中见过了涩———— accept 接收 } }
-
accept 接收,那在现实生活中,爪子是接收? ———— 拿个东西给别人,别人要接收吧
-
所以:void accept( T t )所表达的意思已经非常非常明显了 ———— 如果:还有点懵,那么改动一下 void accept( Object obj ) ————这里只是为了好理解所以用了Object,严格来讲:这个参数类型是由传进来的那个泛型决定的( 所以:注意是支持泛型的啊 )
-
表明:
- 1、传递一个参数给接口,这个接口中的方法( 即:自己要写的业务代码 ),执行完之后,不需要返回值 ( 即:void )
- 2、传递进去的参数可以是任意类型
-
表明:
-
因此:总结————lambda表达式可以执行的 消费者类型的函数式接口是指什么?
- 使用方法时,这个方法的参数是一个接口类型的 ( 注:这个接口要保证只有一个抽象方法,不然lambda识别不了 ,是多个抽象方法的话,它不知道去找哪一个抽象方法)
- 然后传递进去一个 / 多个 / 无参给你( lambda去执行的那个函数 ,即:接口中的那个抽象方法 ),lambda执行完之后不需要给我返回值 ( 即:中间写的那部分业务代码 ) ————这种接口类型的参数问题就可以使用lambda表达式来简化代码
-
所以:void accept( T t )所表达的意思已经非常非常明显了 ———— 如果:还有点懵,那么改动一下 void accept( Object obj ) ————这里只是为了好理解所以用了Object,严格来讲:这个参数类型是由传进来的那个泛型决定的( 所以:注意是支持泛型的啊 )
-
accept 接收,那在现实生活中,爪子是接收? ———— 拿个东西给别人,别人要接收吧
-
-
-
1、消费型( Consumer) ——— 又懵逼,这是啥子鬼玩意儿? ———— 看源码涩
-
再继续研究:函数式接口有哪些类型( 即:分为哪几种 )
-
-
2、供给型( Supplier ),直接上源码
-
@FunctionalInterface public interface Supplier<T> { /** * Gets a result. * * @return a result */ T get(); }
- 传递的接口参数对应的接口中抽象方法是无参数、有返回值类型
-
-
-
-
- 实例:就是前面对TreeSet集合改写排序规则那个例子就是,后面的实例不想写了
-
-
-
-
-
3、断言型( Predicate ),上源码————这个接口别懵了,因为它里面还有其他的抽象方法( 但是真正属于这个接口的只有一个 )
-
@FunctionalInterface public interface Predicate<T> { /** * Evaluates this predicate on the given argument. * * @param t the input argument * @return {@code true} if the input argument matches the predicate, * otherwise {@code false} */ boolean test(T t); }
- 给接口中的抽象方法传递一个任意类型的参数( 自己看情况决定是什么类型 ),然后返回一个boolean值
-
-
3、断言型( Predicate ),上源码————这个接口别懵了,因为它里面还有其他的抽象方法( 但是真正属于这个接口的只有一个 )
-
-
-
-
4、函数型( Function ),也是直接上源码
-
@FunctionalInterface public interface Function<T, R> { /** * Applies this function to the given argument. * * @param t the function argument * @return the function result */ R apply(T t); // R是返回值,t是参数 }
- 给接口中的抽象方法传递一个参数、需要一个任意类型的返回值( 自己控制类型 )
-
-
4、函数型( Function ),也是直接上源码
-
-
-
-
lambda表达式的一些精要
-
lambda表达式的一些精要
-
-
-
-
lambda中的方法引用
-
List<String> list = Arrays.asList("张三", "李四", "王五", "赵六"); // lambda用法 // list.forEach( t-> System.out.println(t) ); // 这是正常玩的,另外forEach语句不说明,就是遍历的一个方法( 自行百度 ) // 方法引用 list.forEach( System.out::println ); // 这是指:遍历list这个集合,然后打印出每一个值( 这里的System.out::println就是方法引用 // ::就是引用的意思
-
-
lambda中的方法引用
-
2、Stream流,不是IO里面的那个流,这里是数据操作流( 也就是一个流程的流 )
-
这个流程是个什么样的?
-
1、来玩儿数据源( 即:创建流 )
-
package cn.xieGongZi.Stream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Demo { public static void main(String[] args) { // 创建流 // 1、通过集合创建流( 最常用,这个东西应用的最多的地方也就是集合中 ) // 先搞一个数据嘛————不过搞复杂一点儿( 因此:再来一个员工类 Employee ) // 开始准备填充数据 //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); // 创建流————1、集合创建 Stream<Employee> stream1 = list.stream(); System.out.println( stream1 ); // java.util.stream.ReferencePipeline$Head@4554617c,就是一个对象,看不出啥 // 创建流嘛,看不出什么东西正常,也比较无聊 // 2、利用Arrays工具类创建 // Arrays.stream(); // 但是:这个需要传递一个任意类型的数组 Stream<Object> stream2 = Arrays.stream( list.toArray() ); System.out.println( stream2 ); // java.util.stream.ReferencePipeline$Head@74a14482 // 3、利用stream接口来创建 Stream<List<Employee>> stream3 = Stream.of(list);// of这里面是一个可变参数 / T类型的参数( 泛型 ) // 所以类型就是依赖前面集合中创建的时候用的泛型类型 System.out.println( stream3 ); // java.util.stream.ReferencePipeline$Head@1540e19d 都是一些对象,看不出啥子东西,玩起也无聊 } }
package cn.xieGongZi.Stream; // 员工类 public class Employee { private String name; private String job; private String sex; private Double salary; public Employee(String name, String job, String sex, Double salary) { this.name = name; this.job = job; this.sex = sex; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", job='" + job + '\'' + ", sex='" + sex + '\'' + ", salary=" + salary + '}'; } }
-
-
-
先提前知道一个点:即:流程图中的最后一环 —— 结束流程( 这里先了解一个forEach,其他的后面进行说明 )
-
让这个点提前了解的原因是:
-
这个流程创建了流之后,需要最后一步:结束流程,不然数据无法显示
-
// 终止流程 ———— 这个有结束流程 并 获取最终结果的功能 ———— 因此:先来了解一个终止方法 // forEach()————这个方法就是遍历的意思。它需要一个消费型函数式接口 stream1.forEach( (e)-> System.out.println(e) ); // 这里的这个e就是Employee类型的对象e // 再次解释一下这个流程 // 首先:我们需要把一个类型的对象 当做参数 丢进去( 即:玩的匿名内部类new哪里————不就是一个对象吗 ) // 然后:这个对象携带的参数( 信息 ) 就交给lambda表达式的某一个函数,让它去执行( 即:这里的forEach ) // 而我们只需要做的事情就是:提供一种类型的对象参数,然后提供这个对象参数进到lambda要执行的函数中的业务代码是什么就行了( 即:这里的输出语句 )
-
-
这个流程创建了流之后,需要最后一步:结束流程,不然数据无法显示
-
让这个点提前了解的原因是:
-
先提前知道一个点:即:流程图中的最后一环 —— 结束流程( 这里先了解一个forEach,其他的后面进行说明 )
-
来正式开始玩儿这个流中的中间重要流程
-
1、filter过滤 ————— 过滤是什么意思?———— 就是 筛选出我想要的信息涩
-
package cn.xieGongZi.Stream.playFilter; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Test { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); // 创建流 Stream<Employee> stream1 = list.stream(); // 开始玩儿filter // 1、假如我只想要list中的演员信息呢? System.out.println("获取list中的演员"); stream1.filter( employee -> employee.getJob().equals("演员") ).forEach( System.out::println ); // 形参只有employee这一个,所以()直接省略 // employee.getJob().equals("演员") 这个就是业务逻辑代码涩 // 可以对照着 我们不知道这个lambda表达式,正常写这种问题的代码,这样理解更深 System.out.println(); System.out.println("正常代码写法"); for (Employee employee : list) { if ( employee.getJob().equals("演员") ){ System.out.println( employee ); } } // 2、如果我想获得职业是演员,但是同时保证还是女的呢? System.out.println(); System.out.println("获取list中的女演员"); Stream<Employee> stream2 = list.stream(); // 这里重写开流,是因为前面那个已经利用forEach把流关闭了 stream2.filter( employee -> employee.getJob().equals("演员") && employee.getSex().equals("女") ).forEach( System.out::println ); // 这个过滤也就这么玩的,就不继续玩儿了 } }
-
效果图如下:
-
-
-
1、filter过滤 ————— 过滤是什么意思?———— 就是 筛选出我想要的信息涩
-
-
2、limit限制 ———— 什么意思? ———— 就是我只想显示特定的几条数据嘛
-
package cn.xieGongZi.Stream.playLimit; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Demo { public static void main(String[] args) { // 准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); // 1、假如我只想要显示前5条数据呢? System.out.println("Stream流使用limit和lambda表达式进行操作"); Stream<Employee> stream1 = list.stream(); stream1.limit(5).forEach( System.out::println ); System.out.println(); // 对比正常流程 System.out.println("这是用正常流程进行遍历前5条数据"); for (int i = 0; i < 5; i++) { System.out.println( list.get(i) ); } // 2、那如果我只想要4、5条数据呢? ———— 用一个方法skip(),在多线程中已经介绍过这个方法了,作用也是一样的 System.out.println(); System.out.println("利用skip和lambda表达式获取stream流中指定那条 / 几条的信息"); Stream<Employee> stream2 = list.stream(); stream2.skip(3).limit(2).forEach(employee -> System.out.println( employee ) ); } }
-
效果图如下:
-
-
2、limit限制 ———— 什么意思? ———— 就是我只想显示特定的几条数据嘛
-
-
3、distinct 去重 ———— 去除重复的数据
- 这个默认是根据Object类中的equals()来进行比较( 而这种默认比较的是值,所以只适合用值来去重,其他的东西需要去重的话,则:需要重写equals()方法,也就会伴随着重写hashCode,因此:这个不多做说明
-
3、distinct 去重 ———— 去除重复的数据
-
-
4、map投影 ———— 获取指定流中的某一部分组成的流
-
package cn.xieGongZi.Stream.playMap; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Demo { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); // 1、如果我只想要list中的所有的Job的信息呢? System.out.println("通过lambda和map映射流中的一部分内容"); Stream<Employee> stream = list.stream(); stream.map( employee -> employee.getJob() ).forEach( employee->System.out.println(employee) ); } }
-
效果图如下:
-
-
4、map投影 ———— 获取指定流中的某一部分组成的流
-
-
5、Sorted排序
-
可以得出:排序规则和treeSet一样的( 实现CompareTo接口 / 现写现用 ),所以,其实不太想进行说明
-
package cn.xieGongZi.Stream.playSorted; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; import java.util.stream.Stream; public class Demo { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); Stream<Employee> stream = list.stream(); stream.sorted( ( employee1 , employee2)-> employee1.getSalary() > employee2.getSalary() ? 1:-1).forEach( employee -> System.out.println(employee) ); } }
-
效果图如下:
-
-
-
5、Sorted排序
-
-
2、玩儿流程中的最后一项:终止操作
- 1、forEach 前面已经玩过了,所以不玩了
-
2、玩儿流程中的最后一项:终止操作
-
-
-
2、min 和 max ———— 获取流中最小 / 最小的那个对象信息 ———— 这个东西就和多线程中的那个异步结果Future一样
-
package cn.xieGongZi.Stream.close.min; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); // 这个规则也是弄一个Comparator,所以还可以对照treeSet的排序原理来理解 Employee employee = list.stream().min((employee1, employee2) -> employee1.getSalary() > employee2.getSalary() ? 1 : -1).get(); System.out.println(employee); System.out.println(); Employee employee3 = list.stream().max((employee1, employee2) -> employee1.getSalary() > employee2.getSalary() ? 1 : -1).get(); System.out.println(employee3); } }
-
- 3、count ———— 获取流中的信息对象有多少个
-
2、min 和 max ———— 获取流中最小 / 最小的那个对象信息 ———— 这个东西就和多线程中的那个异步结果Future一样
-
-
-
-
-
package cn.xieGongZi.Stream.close.count; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; public class Demo { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); System.out.println( list.stream().count() ); System.out.println(); // 还可以配合着玩儿 System.out.println( list.stream().filter( employee -> employee.getSex().equals("男") ).count() ); } }
效果图如下:
-
-
-
-
-
-
4、collect ———— 收集 ———— 这个玩意儿需要一个容器把结果装起来( 因此需要用到Collectors工具类 )
package cn.xieGongZi.Stream.close.collect; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class Demo { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); // 1、低级使用 System.out.println("低级使用"); List<Employee> collect = list.stream().collect( Collectors.toList() ); System.out.println( collect ); System.out.println(); // 2、配合其他的中间操作使用 System.out.println("灵活使用"); List<Employee> resultCollect = list.stream().filter( employee -> employee.getSex().equals("女") ).collect( Collectors.toList() ); System.out.println( resultCollect ); } }
效果图如下:
这个东西补充一个点:利用Conllects工具类在这里还可以实现分组 ——— group
-
而这个的思想就是利用了map集合的思想———— key-value双列存储,但是更复杂( 来个图看一下 )
-
实例:
-
package cn.xieGongZi.Stream.close.collect.group; import cn.xieGongZi.Stream.Employee; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Play { public static void main(String[] args) { //准备数据 List<Employee> list = new ArrayList<>(); list.add(new Employee("刘德华", "歌手", "男", 1200.0)); list.add(new Employee("张旭阳", "演员", "男", 1400.0)); list.add(new Employee("小沈阳", "演员", "男", 1300.0)); list.add(new Employee("王宝强", "演员", "男", 1900.0)); list.add(new Employee("姚明", "歌手", "男", 2200.0)); list.add(new Employee("张杰", "主持人", "男", 3100.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); list.add(new Employee("范冰冰", "演员", "女", 4800.0)); Map< String, List<Employee> > group = list.stream().collect( Collectors.groupingBy(employee -> employee.getJob() ) ); // 这里泛型的泛型 ———— 套娃 ———— 即:整个内容是存在一个map中的 // 而这个map中的key就是job,value就是每一个职业对应有哪些人 // String就是key 职业的类型,list集合中就是存的这个职业对应的是那些人,类型嘛,就是Employee类型咯 for ( String key : group.keySet() ) { System.out.println( key + " = " + group.get(key) ); } } }
-
-
-
-
4、collect ———— 收集 ———— 这个玩意儿需要一个容器把结果装起来( 因此需要用到Collectors工具类 )
-
至此,java8的新特性就整完了,其他的特性也有,只是那些懒得说明了,因为最常用的是这些,其他那些有基础知识之后,需要用时一看就会了
另外:现在已经是java10几了,所以严格来讲,这些根本不叫新特性 ^ _ ^
作者:紫邪情
出 处:https://www.cnblogs.com/xiegongzi/p/15161243.html