VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Java教程 >
  • 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中的抽象方法
                
                    }
                }
                复制代码

 

 

    • 再继续研究:函数式接口有哪些类型( 即:分为哪几种 )
      • 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表达式来简化代码

 

 

    •  
    • 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值

 

      • 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是参数
          }
          复制代码

           

          得出结论:
          • 给接口中的抽象方法传递一个参数、需要一个任意类型的返回值( 自己控制类型 )

 

      • 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就是方法引用
                                                       // ::就是引用的意思
          
          
          复制代码

           

 

 

 

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要执行的函数中的业务代码是什么就行了( 即:这里的输出语句 )
            复制代码

 

 

  • 来正式开始玩儿这个流中的中间重要流程
    • 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 );
                // 这个过滤也就这么玩的,就不继续玩儿了
        
        
            }
        }
        复制代码
      • 效果图如下:
        •  

           

 

 

    • 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 ) );
        
        
            }
        }
        复制代码
      •  效果图如下:

 

 

    • 3、distinct 去重 ———— 去除重复的数据
      • 这个默认是根据Object类中的equals()来进行比较( 而这种默认比较的是值,所以只适合用值来去重,其他的东西需要去重的话,则:需要重写equals()方法,也就会伴随着重写hashCode,因此:这个不多做说明

 

 

    • 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) );
            }
        }
        复制代码
      •  效果图如下:

 

 

    • 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) );
              }
          }
          复制代码
        • 效果图如下:

 

 

 

    • 2、玩儿流程中的最后一项:终止操作
      • 1、forEach 前面已经玩过了,所以不玩了

 

      • 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 ———— 获取流中的信息对象有多少个
        • 复制代码
          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) );
              
                      }
                  }
              }
              复制代码
              效果图如下:
              •  

                 

至此,java8的新特性就整完了,其他的特性也有,只是那些懒得说明了,因为最常用的是这些,其他那些有基础知识之后,需要用时一看就会了

另外:现在已经是java10几了,所以严格来讲,这些根本不叫新特性 ^ _ ^

 

 

作者:紫邪情

出  处:
https://www.cnblogs.com/xiegongzi/p/15161243.html



相关教程