Java8 新特性

新特性简介:

     在很多情况下,Java8都能提升应用性能,而无需任何改变或性能调优。

     Lambda 表达式、 Streams API 以及现有类的新方法都是提高生产力的重要工具。

     Java8 新推出的 Optional 类型在处理 null 值时,能减少 NullPointerExceptions 的可能性,给开发者极大的灵活度。

     具体如下:

 

1.速度更快 

     Java8 运行应用时速度更快。通常,升级至 Java8 的应用都能得到速度上的提升,即便没有做任何改变或调优。对于为了迎合特定 JVM 而做出调整的应用,这或许并不适用。但 Java8 性能更优的理由还有很多:

     (1)数据结构的性能提升:对广受欢迎的 HashMap 进行的基准测试表明,它们在 Java8 中的性能更好。这种提升非常吸引人,你无需学习新的 Streams API 或 Lambda 语法,甚至不需要改变现有的代码,就能提升应用的性能。

     ① 在之前HashMap采用数组和链表的存储结构,但是现在还除了原有的数组和链表,还添加了红黑数,使得查询的效率更高。

     a.HashMap本质是一个散列表,存储元素为键值对;

     b.HashMap继承AbstractMap,实现了Map、Cloneable、java.io.Serializable接口;

     c.HashMap的是线程不安全的,它的key、value都可以为null; 

          final int loadFacotr

          static final float DEFAULT_LOAD_FACTOR: 默认装填因子0.75,如果当前键值对个数 >= HashMap最大容量*装填因子,进行rehash操作;

          int threshold

          static final int TREEIFY_THRESHOLD: JDK1.8 新加,Entry链表最大长度,当桶中节点数目大于该长度时,将链表转成红黑树存储;

          static final int UNTREEIFY_THRESHOLD:JDK1.8 新加,当桶中节点数小于该长度,将红黑树转为链表存储;

          static final int DEFAULT_INITIAL_CAPACITY: 默认键值队个数为16;

transient Node<K, V>[] table:键值对数组,长度动态增加,但是总为2的幂;用transient修饰表示对象序列化时该字段不可被序列化;

     ② ConcurrentHashMap 原理:在JDK1.6中,ConcurrentHashMap将数据分成一段一段存储,给每一段数据配一把锁,当一个线程获得锁互斥访问一个段数据时,其他段的数据也可被其他线程访问;每个Segment拥有一把可重入锁,因此ConcurrentHashMap的分段锁数目即为Segment数组长度。ConcurrentHashMap结构:每一个segment都是一个HashEntry<K,V>[] table, table中的每一个元素本质上都是一个HashEntry的单向队列(单向链表实现)。每一个segment都是一个HashEntry<K,V>[] table, table中的每一个元素本质上都是一个HashEntry的单向队列。

     在JDK1.8中采用CAS(Compare And Swap)无锁算法算法:CAS算法包含三个参数CAS(V, E, N),判断预期值E和内存旧值是否相同(Compare),如果相等用新值N覆盖旧值V(Swap),否则失败; 当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,其他线程失败(失败线程不会被阻塞,而是被告知“失败”,可以继续尝试),CAS在硬件层面可以被编译为机器指令执行,因此性能高于基于锁占有方式实现线程安全。

     与JDK1.6相比JDK1.8具有如下优势:

     a.JDK 1.8取消类segments字段,直接用table数组存储键值对,JDK1.6中每个bucket中键值对组织方式是单向链表,查找复杂度是O(n),JDK1.8中当链表长度超过TREEIFY_THRESHOLD时,链表转换为红黑树,查询复杂度可以降低到O(log n),改进性能;

     b.JDK1.8中,一个线程每次对一个桶(链表 or 红黑树)进行加锁,其他线程仍然可以访问其他桶;

     c.ConcurrentHashMap底层数据结构与HashMap相同,仍然采用table数组+链表+红黑树结构;

        一个线程进行put/remove操作时,对桶(链表 or 红黑树)加上synchronized独占锁;

        ConcurrentHashMap采用CAS算法保证线程安全;

     (2)垃圾回收器提升:通常,Java 应用性能取决于垃圾回收的效率。的确,糟糕的垃圾回收会很大程度上影响应用性能。Java8 对垃圾回收做了很多改变,能有效提升性能并简化调优。最为人熟知的改变是 PermGen 的移除与 Metaspace 的引入。

     (3)Fork/Join 速度提升:fork/join 框架是在 Java7 中首次引入的,目的是简化使用 JVM 的并发程序。Java8 中投入了很多努力进一步提升该框架。现在,fork/join 在 Streams API 中用于并发操作。

     此外,Java8 中还包含诸多改进以支持并发。Oracle 在 JDK 8 中总结了这些性能提升。

 

2.Lambda表达式

     Lambda表达式的目的使得代码更少,Java 经常被人们诟病其样本代码太多。为此,Java8 新的 API 采用了更具功能性的方式,专注于实现什么而不是如何实现。

     Java8 中的 Lambda 表达式不仅是 Java 已有的匿名内部类,Java8 推出之前传递行为的方法之外的语法糖衣。Lambda 表达式采用了 Java 7 的内部改变,因此运用起来相当流畅。想了解如何使用 Lambda 表达式简化代码,请继续阅读。

(1)Lambdal表达试代码简单示例:

[java] view plain copy

  1. public class TestLambda1 {  
  2.   
  3.    //原来的匿名内部类  
  4.    @Test  
  5.    public void test1(){  
  6.       Comparator<String> com = new Comparator<String>(){  
  7.          @Override  
  8.          public int compare(String o1, String o2) {  
  9.             return Integer.compare(o1.length(), o2.length());  
  10.          }  
  11.       };  
  12.       TreeSet<String> ts = new TreeSet<>(com);  
  13.       TreeSet<String> ts2 = new TreeSet<>(new Comparator<String>(){  
  14.          @Override  
  15.          public int compare(String o1, String o2) {  
  16.             return Integer.compare(o1.length(), o2.length());  
  17.          }  
  18.       });  
  19.    }  
  20.   
  21.    //现在的 Lambda 表达式  
  22.    @Test  
  23.    public void test2(){  
  24.       Comparator<String> com = (x, y) -> Integer.compare(x.length(), y.length());  
  25.       TreeSet<String> ts = new TreeSet<>(com);  
  26.    }  
  27.   
  28.   
  29.    List<Employee> emps = Arrays.asList(  
  30.          new Employee(101"张三"189999.99),  
  31.          new Employee(102"李四"596666.66),  
  32.          new Employee(103"王五"283333.33),  
  33.          new Employee(104"赵六"87777.77),  
  34.          new Employee(105"田七"385555.55)  
  35.    );  
  36.   
  37.    //需求:获取公司中年龄小于 35 的员工信息  
  38.    public List<Employee> filterEmployeeAge(List<Employee> emps){  
  39.       List<Employee> list = new ArrayList<>();  
  40.       for (Employee emp : emps) {  
  41.          if(emp.getAge() <= 35){  
  42.             list.add(emp);  
  43.          }  
  44.       }  
  45.       return list;  
  46.    }  
  47.      
  48.    @Test  
  49.    public void test3(){  
  50.       List<Employee> list = filterEmployeeAge(emps);  
  51.       for (Employee employee : list) {  
  52.          System.out.println(employee);  
  53.       }  
  54.    }  
  55.      
  56.    //需求:获取公司中工资大于 5000 的员工信息  
  57.    public List<Employee> filterEmployeeSalary(List<Employee> emps){  
  58.       List<Employee> list = new ArrayList<>();  
  59.       for (Employee emp : emps) {  
  60.          if(emp.getSalary() >= 5000){  
  61.             list.add(emp);  
  62.          }  
  63.       }  
  64.       return list;  
  65.    }  
  66.      
  67.    //优化方式一:策略设计模式  
  68.    public List<Employee> filterEmployee(List<Employee> emps, MyPredicate<Employee> mp){  
  69.       List<Employee> list = new ArrayList<>();  
  70.       for (Employee employee : emps) {  
  71.          if(mp.test(employee)){  
  72.             list.add(employee);  
  73.          }  
  74.       }  
  75.       return list;  
  76.    }  
  77.      
  78.    @Test  
  79.    public void test4(){  
  80.       List<Employee> list = filterEmployee(emps, new FilterEmployeeForAge());  
  81.       for (Employee employee : list) {  
  82.          System.out.println(employee);  
  83.       }  
  84.         
  85.       System.out.println("------------------------------------------");  
  86.         
  87.       List<Employee> list2 = filterEmployee(emps, new FilterEmployeeForSalary());  
  88.       for (Employee employee : list2) {  
  89.          System.out.println(employee);  
  90.       }  
  91.    }  
  92.      
  93.    //优化方式二:匿名内部类  
  94.    @Test  
  95.    public void test5(){  
  96.       List<Employee> list = filterEmployee(emps, new MyPredicate<Employee>() {  
  97.          @Override  
  98.          public boolean test(Employee t) {  
  99.             return t.getId() <= 103;  
  100.          }  
  101.       });  
  102.       for (Employee employee : list) {  
  103.          System.out.println(employee);  
  104.       }  
  105.    }  
  106.      
  107.    //优化方式三:Lambda 表达式  
  108.    @Test  
  109.    public void test6(){  
  110.       List<Employee> list = filterEmployee(emps, (e) -> e.getAge() <= 35);  
  111.       list.forEach(System.out::println);  
  112.         
  113.       System.out.println("------------------------------------------");  
  114.         
  115.       List<Employee> list2 = filterEmployee(emps, (e) -> e.getSalary() >= 5000);  
  116.       list2.forEach(System.out::println);  
  117.    }  
  118.      
  119.    //优化方式四:Stream API  
  120.    @Test  
  121.    public void test7(){  
  122.       emps.stream()  
  123.          .filter((e) -> e.getAge() <= 35)  
  124.          .forEach(System.out::println);  
  125.         
  126.       System.out.println("----------------------------------------------");  
  127.         
  128.       emps.stream()  
  129.          .map(Employee::getName)  
  130.          .limit(3)  
  131.          .sorted()  
  132.          .forEach(System.out::println);  
  133.    }  
  134. }  

(2)Lambdal语法格式介绍

[java] view plain copy

  1. /* 
  2.  * 一、Lambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或 Lambda 操作符 
  3.  *                        箭头操作符将 Lambda 表达式拆分成两部分: 
  4.  *  
  5.  * 左侧:Lambda 表达式的参数列表 
  6.  * 右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体 
  7.  *  
  8.  * 语法格式一:无参数,无返回值 
  9.  *        () -> System.out.println("Hello Lambda!"); 
  10.  *  
  11.  * 语法格式二:有一个参数,并且无返回值 
  12.  *        (x) -> System.out.println(x) 
  13.  *  
  14.  * 语法格式三:若只有一个参数,小括号可以省略不写 
  15.  *        x -> System.out.println(x) 
  16.  *  
  17.  * 语法格式四:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句 
  18.  *    Comparator<Integer> com = (x, y) -> { 
  19.  *       System.out.println("函数式接口"); 
  20.  *       return Integer.compare(x, y); 
  21.  *    }; 
  22.  * 
  23.  * 语法格式五:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写 
  24.  *        Comparator<Integer> com = (x, y) -> Integer.compare(x, y); 
  25.  *  
  26.  * 语法格式六:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断” 
  27.  *        (Integer x, Integer y) -> Integer.compare(x, y); 
  28.  *  
  29.  * 上联:左右遇一括号省 
  30.  * 下联:左侧推断类型省 
  31.  * 横批:能省则省 
  32.  *  
  33.  * 二、Lambda 表达式需要“函数式接口”的支持 
  34.  * 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。 可以使用注解 @FunctionalInterface 修饰 
  35.  *            可以检查是否是函数式接口 
  36.  */  
  37. public class TestLambda2 {  
  38.      
  39.    @Test  
  40.    public void test1(){  
  41.       int num = 0;//jdk 1.7 前,必须是 final  
  42.       Runnable r = new Runnable() {  
  43.          @Override  
  44.          public void run() {  
  45.             System.out.println("Hello World!" + num);  
  46.          }  
  47.       };  
  48.       r.run();  
  49.       System.out.println("-------------------------------");  
  50.       Runnable r1 = () -> System.out.println("Hello Lambda!");  
  51.       r1.run();  
  52.    }  
  53.      
  54.    @Test  
  55.    public void test2(){  
  56.       Consumer<String> con = x -> System.out.println(x);  
  57.       con.accept("我硅谷威武!");  
  58.    }  
  59.      
  60.    @Test  
  61.    public void test3(){  
  62.       Comparator<Integer> com = (x, y) -> {  
  63.          System.out.println("函数式接口");  
  64.          return Integer.compare(x, y);  
  65.       };  
  66.    }  
  67.      
  68.    @Test  
  69.    public void test4(){  
  70.       Comparator<Integer> com = (x, y) -> Integer.compare(x, y);  
  71.    }  
  72.      
  73.    @Test  
  74.    public void test5(){  
  75.       List<String> list = new ArrayList<>();  
  76.       show(new HashMap<>());  
  77.    }  
  78.   
  79.    public void show(Map<String, Integer> map){  
  80.         
  81.    }  
  82.      
  83.    //需求:对一个数进行运算  
  84.    @Test  
  85.    public void test6(){  
  86.       Integer num = operation(100, (x) -> x * x);  
  87.       System.out.println(num);  
  88.       System.out.println(operation(200, (y) -> y + 200));  
  89.    }  
  90.      
  91.    public Integer operation(Integer num, MyFun mf){  
  92.       return mf.getValue(num);  
  93.    }  
  94. }  

3.函数式接口

     Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为 默认方法 不算抽象方法,所以你也可以给你的函数式接口添加默认方法。

     我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加 @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。

[java] view plain copy

  1. @FunctionalInterface  
  2. interface Converter<F, T> {  
  3.     T convert(F from);  
  4. }  
  5. Converter<String, Integer> converter = (from) -> Integer.valueOf(from);  
  6. Integer converted = converter.convert("123");  
  7. System.out.println(converted);   

     需要注意如果@FunctionalInterface如果没有指定,上面的代码也是对的。将lambda表达式映射到一个单方法的接口上,这种做法在Java 8之前就有别的语言实现,比如Rhino JavaScript解释器,如果一个函数参数接收一个单方法的接口而你传递的是一个function,Rhino 解释器会自动做一个单接口的实例到function的适配器,典型的应用场景有 org.w3c.dom.events.EventTarget 的addEventListener 第二个参数 EventListener。

     Java8 内置的四大核心函数式接口

[java] view plain copy

  1. public class TestLambda3 {  
  2.      
  3.    //Predicate<T> 断言型接口:  
  4.    @Test  
  5.    public void test4(){  
  6.       List<String> list = Arrays.asList("Hello""guigu""Lambda""www""ok");  
  7.       List<String> strList = filterStr(list, (s) -> s.length() > 3);  
  8.       for (String str : strList) {  
  9.          System.out.println(str);  
  10.       }  
  11.    }  
  12.      
  13.    //需求:将满足条件的字符串,放入集合中  
  14.    public List<String> filterStr(List<String> list, Predicate<String> pre){  
  15.       List<String> strList = new ArrayList<>();  
  16.       for (String str : list) {  
  17.          if(pre.test(str)){  
  18.             strList.add(str);  
  19.          }  
  20.       }  
  21.       return strList;  
  22.    }  
  23.      
  24.    //Function<T, R> 函数型接口:  
  25.    @Test  
  26.    public void test3(){  
  27.       String newStr = strHandler("\t\t\t 我尚硅谷威武   ", (str) -> str.trim());  
  28.       System.out.println(newStr);  
  29.       String subStr = strHandler("我尚硅谷威武", (str) -> str.substring(25));  
  30.       System.out.println(subStr);  
  31.    }  
  32.      
  33.    //需求:用于处理字符串  
  34.    public String strHandler(String str, Function<String, String> fun){  
  35.       return fun.apply(str);  
  36.    }  
  37.    //Supplier<T> 供给型接口 :  
  38.    @Test  
  39.    public void test2(){  
  40.       List<Integer> numList = getNumList(10, () -> (int)(Math.random() * 100));  
  41.         
  42.       for (Integer num : numList) {  
  43.          System.out.println(num);  
  44.       }  
  45.    }  
  46.      
  47.    //需求:产生指定个数的整数,并放入集合中  
  48.    public List<Integer> getNumList(int num, Supplier<Integer> sup){  
  49.       List<Integer> list = new ArrayList<>();  
  50.       for (int i = 0; i < num; i++) {  
  51.          Integer n = sup.get();  
  52.          list.add(n);  
  53.       }  
  54.       return list;  
  55.    }  
  56.      
  57.    //Consumer<T> 消费型接口 :  
  58.    @Test  
  59.    public void test1(){  
  60.       happy(10000, (m) -> System.out.println("你们Tom喜欢大宝剑,每次消费:" + m + "元"));  
  61.    }   
  62.      
  63.    public void happy(double money, Consumer<Double> con){  
  64.       con.accept(money);  
  65.    }  
  66. }  

4.方法引用与构造器引用

[java] view plain copy

  1. /* 
  2.  * 一、方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用 
  3.  *             (可以将方法引用理解为 Lambda 表达式的另外一种表现形式) 
  4.  *  
  5.  * 1. 对象的引用 :: 实例方法名 
  6.  *  
  7.  * 2. 类名 :: 静态方法名 
  8.  *  
  9.  * 3. 类名 :: 实例方法名 
  10.  *  
  11.  * 注意: 
  12.  *      ①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致! 
  13.  *      ②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName 
  14.  *  
  15.  * 二、构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致! 
  16.  *  
  17.  * 1. 类名 :: new 
  18.  *  
  19.  * 三、数组引用 
  20.  *  
  21.  *     类型[] :: new; 
  22.  *  
  23.  *  
  24.  */  
  25. public class TestMethodRef {  
  26.      
  27.    //数组引用  
  28.    @Test  
  29.    public void test8(){  
  30.       Function<Integer, String[]> fun = (args) -> new String[args];  
  31.       String[] strs = fun.apply(10);  
  32.       System.out.println(strs.length);  
  33.         
  34.       System.out.println("--------------------------");  
  35.         
  36.       Function<Integer, Employee[]> fun2 = Employee[] :: new;  
  37.       Employee[] emps = fun2.apply(20);  
  38.       System.out.println(emps.length);  
  39.    }  
  40.      
  41.    //构造器引用  
  42.    @Test  
  43.    public void test7(){  
  44.       Function<String, Employee> fun = Employee::new;  
  45.       BiFunction<String, Integer, Employee> fun2 = Employee::new;  
  46.    }  
  47.      
  48.    @Test  
  49.    public void test6(){  
  50.       Supplier<Employee> sup = () -> new Employee();  
  51.       System.out.println(sup.get());  
  52.         
  53.       System.out.println("------------------------------------");  
  54.         
  55.       Supplier<Employee> sup2 = Employee::new;  
  56.       System.out.println(sup2.get());  
  57.    }  
  58.      
  59.    //类名 :: 实例方法名  
  60.    @Test  
  61.    public void test5(){  
  62.       BiPredicate<String, String> bp = (x, y) -> x.equals(y);  
  63.       System.out.println(bp.test("abcde""abcde"));  
  64.         
  65.       System.out.println("-----------------------------------------");  
  66.         
  67.       BiPredicate<String, String> bp2 = String::equals;  
  68.       System.out.println(bp2.test("abc""abc"));  
  69.         
  70.       System.out.println("-----------------------------------------");  
  71.         
  72.         
  73.       Function<Employee, String> fun = (e) -> e.show();  
  74.       System.out.println(fun.apply(new Employee()));  
  75.         
  76.       System.out.println("-----------------------------------------");  
  77.         
  78.       Function<Employee, String> fun2 = Employee::show;  
  79.       System.out.println(fun2.apply(new Employee()));  
  80.         
  81.    }  
  82.      
  83.    //类名 :: 静态方法名  
  84.    @Test  
  85.    public void test4(){  
  86.       Comparator<Integer> com = (x, y) -> Integer.compare(x, y);  
  87.         
  88.       System.out.println("-------------------------------------");  
  89.         
  90.       Comparator<Integer> com2 = Integer::compare;  
  91.    }  
  92.      
  93.    @Test  
  94.    public void test3(){  
  95.       BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);  
  96.       System.out.println(fun.apply(1.522.2));  
  97.         
  98.       System.out.println("--------------------------------------------------");  
  99.         
  100.       BiFunction<Double, Double, Double> fun2 = Math::max;  
  101.       System.out.println(fun2.apply(1.21.5));  
  102.    }  
  103.   
  104.    //对象的引用 :: 实例方法名  
  105.    @Test  
  106.    public void test2(){  
  107.       Employee emp = new Employee(101"张三"189999.99);  
  108.         
  109.       Supplier<String> sup = () -> emp.getName();  
  110.       System.out.println(sup.get());  
  111.         
  112.       System.out.println("----------------------------------");  
  113.         
  114.       Supplier<String> sup2 = emp::getName;  
  115.       System.out.println(sup2.get());  
  116.    }  
  117.      
  118.    @Test  
  119.    public void test1(){  
  120.       PrintStream ps = System.out;  
  121.       Consumer<String> con = (str) -> ps.println(str);  
  122.       con.accept("Hello World!");  
  123.         
  124.       System.out.println("--------------------------------");  
  125.         
  126.       Consumer<String> con2 = ps::println;  
  127.       con2.accept("Hello Java8!");  
  128.         
  129.       Consumer<String> con3 = System.out::println;  
  130.    }  
  131.      
  132. }  

5.Stream API

Stream API 的操作步骤:

1. 创建 Stream

2. 中间操作

3. 终止操作(终端操作)

(1)创建 Stream

[java] view plain copy

  1. public class TestStreamaAPI {  
  2.      
  3.    //1. 创建 Stream  
  4.    @Test  
  5.    public void test1(){  
  6.       //1. Collection 提供了两个方法  stream() 与 parallelStream()  
  7.       List<String> list = new ArrayList<>();  
  8.       Stream<String> stream = list.stream(); //获取一个顺序流  
  9.       Stream<String> parallelStream = list.parallelStream(); //获取一个并行流  
  10.         
  11.       //2. 通过 Arrays 中的 stream() 获取一个数组流  
  12.       Integer[] nums = new Integer[10];  
  13.       Stream<Integer> stream1 = Arrays.stream(nums);  
  14.         
  15.       //3. 通过 Stream 类中静态方法 of()  
  16.       Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);  
  17.         
  18.       //4. 创建无限流  
  19.       //迭代  
  20.       Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);  
  21.       stream3.forEach(System.out::println);  
  22.         
  23.       //生成  
  24.       Stream<Double> stream4 = Stream.generate(Math::random).limit(2);  
  25.       stream4.forEach(System.out::println);  
  26.         
  27.    }  
  28. }  

(2)中间操作

[java] view plain copy

  1. //中间操作  
  2. public class TestStreamAPI1 {  
  3.      
  4.    List<Employee> emps = Arrays.asList(  
  5.          new Employee(102"李四"596666.66),  
  6.          new Employee(101"张三"189999.99),  
  7.          new Employee(103"王五"283333.33),  
  8.          new Employee(104"赵六"87777.77),  
  9.          new Employee(104"赵六"87777.77),  
  10.          new Employee(104"赵六"87777.77),  
  11.          new Employee(105"田七"385555.55)  
  12.    );  
  13.   
  14.    /* 
  15.        筛选与切片 
  16.       filter——接收 Lambda , 从流中排除某些元素。 
  17.       limit——截断流,使其元素不超过给定数量。 
  18.       skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 
  19.       distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 
  20.     */  
  21.   
  22.    //内部迭代:迭代操作 Stream API 内部完成  
  23.    @Test  
  24.    public void test1(){  
  25.       //所有的中间操作不会做任何的处理  
  26.       Stream<Employee> stream = emps.stream()  
  27.             .filter((e) -> {  
  28.                System.out.println("测试中间操作");  
  29.                return e.getAge() <= 35;  
  30.             });  
  31.       //只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”  
  32.       stream.forEach(System.out::println);  
  33.    }  
  34.   
  35.    //外部迭代  
  36.    @Test  
  37.    public void test2(){  
  38.       Iterator<Employee> it = emps.iterator();  
  39.       while(it.hasNext()){  
  40.          System.out.println(it.next());  
  41.       }  
  42.    }  
  43.   
  44.    @Test  
  45.    public void test3(){  
  46.       emps.stream()  
  47.             .filter((e) -> {  
  48.                System.out.println("短路!"); // &&  ||  
  49.                return e.getSalary() >= 5000;  
  50.             }).limit(3)  
  51.             .forEach(System.out::println);  
  52.    }  
  53.   
  54.    @Test  
  55.    public void test4(){  
  56.       emps.parallelStream()  
  57.             .filter((e) -> e.getSalary() >= 5000)  
  58.             .skip(2)  
  59.             .forEach(System.out::println);  
  60.    }  
  61.   
  62.    @Test  
  63.    public void test5(){  
  64.       emps.stream()  
  65.             .distinct()  
  66.             .forEach(System.out::println);  
  67.    }  
  68.   
  69.    /* 
  70.       映射 
  71.       map——接收 Lambda , 将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 
  72.       flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 
  73.     */  
  74.    @Test  
  75.    public void test6(){  
  76.       Stream<String> str = emps.stream()  
  77.          .map((e) -> e.getName());  
  78.       System.out.println("-------------------------------------------");  
  79.       List<String> strList = Arrays.asList("aaa""bbb""ccc""ddd""eee");  
  80.       Stream<String> stream = strList.stream()  
  81.             .map(String::toUpperCase);  
  82.       stream.forEach(System.out::println);  
  83.       Stream<Stream<Character>> stream2 = strList.stream()  
  84.             .map(TestStreamAPI1::filterCharacter);  
  85.       stream2.forEach((sm) -> {  
  86.          sm.forEach(System.out::println);  
  87.       });  
  88.       System.out.println("---------------------------------------------");  
  89.       Stream<Character> stream3 = strList.stream()  
  90.             .flatMap(TestStreamAPI1::filterCharacter);  
  91.         
  92.       stream3.forEach(System.out::println);  
  93.    }  
  94.   
  95.    public static Stream<Character> filterCharacter(String str){  
  96.       List<Character> list = new ArrayList<>();  
  97.         
  98.       for (Character ch : str.toCharArray()) {  
  99.          list.add(ch);  
  100.       }  
  101.       return list.stream();  
  102.    }  
  103.      
  104.    /* 
  105.       sorted()——自然排序 
  106.       sorted(Comparator com)——定制排序 
  107.     */  
  108.    @Test  
  109.    public void test7(){  
  110.       emps.stream()  
  111.          .map(Employee::getName)  
  112.          .sorted()  
  113.          .forEach(System.out::println);  
  114.       System.out.println("------------------------------------");  
  115.       emps.stream()  
  116.          .sorted((x, y) -> {  
  117.             if(x.getAge() == y.getAge()){  
  118.                return x.getName().compareTo(y.getName());  
  119.             }else{  
  120.                return Integer.compare(x.getAge(), y.getAge());  
  121.             }  
  122.          }).forEach(System.out::println);  
  123.    }  
  124. }  

(3)终止操作

[java] view plain copy

  1. //3. 终止操作  
  2. /* 
  3.    allMatch——检查是否匹配所有元素 
  4.    anyMatch——检查是否至少匹配一个元素 
  5.    noneMatch——检查是否没有匹配的元素 
  6.    findFirst——返回第一个元素 
  7.    findAny——返回当前流中的任意元素 
  8.    count——返回流中元素的总个数 
  9.    max——返回流中最大值 
  10.    min——返回流中最小值 
  11.  */  
  12. public class TestStreamAPI2 {  
  13.   
  14.    List<Employee> emps = Arrays.asList(  
  15.          new Employee(102"李四"596666.66, Status.BUSY),  
  16.          new Employee(101"张三"189999.99, Status.FREE),  
  17.          new Employee(103"王五"283333.33, Status.VOCATION),  
  18.          new Employee(104"赵六"87777.77, Status.BUSY),  
  19.          new Employee(104"赵六"87777.77, Status.FREE),  
  20.          new Employee(104"赵六"87777.77, Status.FREE),  
  21.          new Employee(105"田七"385555.55, Status.BUSY)  
  22.    );  
  23.   
  24.    @Test  
  25.    public void test1(){  
  26.          boolean bl = emps.stream()  
  27.             .allMatch((e) -> e.getStatus().equals(Status.BUSY));  
  28.            
  29.          System.out.println(bl);  
  30.            
  31.          boolean bl1 = emps.stream()  
  32.             .anyMatch((e) -> e.getStatus().equals(Status.BUSY));  
  33.            
  34.          System.out.println(bl1);  
  35.            
  36.          boolean bl2 = emps.stream()  
  37.             .noneMatch((e) -> e.getStatus().equals(Status.BUSY));  
  38.            
  39.          System.out.println(bl2);  
  40.    }  
  41.      
  42.    @Test  
  43.    public void test2(){  
  44.       Optional<Employee> op = emps.stream()  
  45.          .sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))  
  46.          .findFirst();  
  47.       System.out.println(op.get());  
  48.       System.out.println("--------------------------------");  
  49.       Optional<Employee> op2 = emps.parallelStream()  
  50.          .filter((e) -> e.getStatus().equals(Status.FREE))  
  51.          .findAny();  
  52.       System.out.println(op2.get());  
  53.    }  
  54.      
  55.    @Test  
  56.    public void test3(){  
  57.       long count = emps.stream()  
  58.                    .filter((e) -> e.getStatus().equals(Status.FREE))  
  59.                    .count();  
  60.       System.out.println(count);  
  61.       Optional<Double> op = emps.stream()  
  62.          .map(Employee::getSalary)  
  63.          .max(Double::compare);  
  64.       System.out.println(op.get());  
  65.       Optional<Employee> op2 = emps.stream()  
  66.          .min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));  
  67.       System.out.println(op2.get());  
  68.    }  
  69.      
  70.    //注意:流进行了终止操作后,不能再次使用  
  71.    @Test  
  72.    public void test4(){  
  73.       Stream<Employee> stream = emps.stream()  
  74.        .filter((e) -> e.getStatus().equals(Status.FREE));  
  75.       long count = stream.count();  
  76.       stream.map(Employee::getSalary)  
  77.          .max(Double::compare);  
  78.    }  
  79.   
  80.    @Test  
  81.    public void test5(){  
  82.       List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);  
  83.       Integer sum = list.stream()  
  84.             .reduce(0, (x, y) -> x + y);  
  85.       System.out.println(sum);  
  86.       System.out.println("----------------------------------------");  
  87.       Optional<Double> op = emps.stream()  
  88.             .map(Employee::getSalary)  
  89.             .reduce(Double::sum);  
  90.       System.out.println(op.get());  
  91.    }  
  92.   
  93.    //需求:搜索名字中 “六” 出现的次数  
  94.    @Test  
  95.    public void test6(){  
  96.       Optional<Integer> sum = emps.stream()  
  97.             .map(Employee::getName)  
  98.             .flatMap(TestStreamAPI1::filterCharacter)  
  99.             .map((ch) -> {  
  100.                if(ch.equals('六'))  
  101.                   return 1;  
  102.                else  
  103.                   return 0;  
  104.             }).reduce(Integer::sum);  
  105.   
  106.       System.out.println(sum.get());  
  107.    }  
  108.   
  109.    //collect——将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法  
  110.    @Test  
  111.    public void test7(){  
  112.       List<String> list = emps.stream()  
  113.             .map(Employee::getName)  
  114.             .collect(Collectors.toList());  
  115.   
  116.       list.forEach(System.out::println);  
  117.   
  118.       System.out.println("----------------------------------");  
  119.   
  120.       Set<String> set = emps.stream()  
  121.             .map(Employee::getName)  
  122.             .collect(Collectors.toSet());  
  123.   
  124.       set.forEach(System.out::println);  
  125.   
  126.       System.out.println("----------------------------------");  
  127.   
  128.       HashSet<String> hs = emps.stream()  
  129.             .map(Employee::getName)  
  130.             .collect(Collectors.toCollection(HashSet::new));  
  131.   
  132.       hs.forEach(System.out::println);  
  133.    }  
  134.   
  135.    @Test  
  136.    public void test8(){  
  137.       Optional<Double> max = emps.stream()  
  138.             .map(Employee::getSalary)  
  139.             .collect(Collectors.maxBy(Double::compare));  
  140.   
  141.       System.out.println(max.get());  
  142.   
  143.       Optional<Employee> op = emps.stream()  
  144.             .collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));  
  145.   
  146.       System.out.println(op.get());  
  147.   
  148.       Double sum = emps.stream()  
  149.             .collect(Collectors.summingDouble(Employee::getSalary));  
  150.   
  151.       System.out.println(sum);  
  152.   
  153.       Double avg = emps.stream()  
  154.             .collect(Collectors.averagingDouble(Employee::getSalary));  
  155.   
  156.       System.out.println(avg);  
  157.   
  158.       Long count = emps.stream()  
  159.             .collect(Collectors.counting());  
  160.   
  161.       System.out.println(count);  
  162.   
  163.       System.out.println("--------------------------------------------");  
  164.   
  165.       DoubleSummaryStatistics dss = emps.stream()  
  166.             .collect(Collectors.summarizingDouble(Employee::getSalary));  
  167.   
  168.       System.out.println(dss.getMax());  
  169.    }  
  170.   
  171.    //分组  
  172.    @Test  
  173.    public void test9(){  
  174.       Map<Status, List<Employee>> map = emps.stream()  
  175.             .collect(Collectors.groupingBy(Employee::getStatus));  
  176.       System.out.println(map);  
  177.    }  
  178.   
  179.    //多级分组  
  180.    @Test  
  181.    public void test10(){  
  182.       Map<Status, Map<String, List<Employee>>> map = emps.stream()  
  183.             .collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {  
  184.                if(e.getAge() >= 60)  
  185.                   return "老年";  
  186.                else if(e.getAge() >= 35)  
  187.                   return "中年";  
  188.                else  
  189.                   return "成年";  
  190.             })));  
  191.       System.out.println(map);  
  192.    }  
  193.   
  194.    //分区  
  195.    @Test  
  196.    public void test11(){  
  197.       Map<Boolean, List<Employee>> map = emps.stream()  
  198.             .collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));  
  199.       System.out.println(map);  
  200.    }  
  201.   
  202.    @Test  
  203.    public void test12(){  
  204.       String str = emps.stream()  
  205.             .map(Employee::getName)  
  206.             .collect(Collectors.joining("," , "----""----"));  
  207.       System.out.println(str);  
  208.    }  
  209.   
  210.    @Test  
  211.    public void test13(){  
  212.       Optional<Double> sum = emps.stream()  
  213.             .map(Employee::getSalary)  
  214.             .collect(Collectors.reducing(Double::sum));  
  215.       System.out.println(sum.get());  
  216.    }  
  217.   
  218. }  

6.接口中的默认方法与静态方法

7.新时间日期API

(1) TestSimpleDateFormat

[java] view plain copy

  1. public class TestSimpleDateFormat {  
  2.    public static void main(String[] args) throws Exception {  
  3.       DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");  
  4.       Callable<LocalDate> task = new Callable<LocalDate>() {  
  5.          @Override  
  6.          public LocalDate call() throws Exception {  
  7.             LocalDate ld = LocalDate.parse("20161121", dtf);  
  8.             return ld;  
  9.          }  
  10.       };  
  11.   
  12.       ExecutorService pool = Executors.newFixedThreadPool(10);  
  13.       List<Future<LocalDate>> results = new ArrayList<>();  
  14.       for (int i = 0; i < 10; i++) {  
  15.          results.add(pool.submit(task));  
  16.       }  
  17.       for (Future<LocalDate> future : results) {  
  18.          System.out.println(future.get());  
  19.       }  
  20.       pool.shutdown();  
  21.    }  
  22. }  

(2) TestLocalDateTime

[java] view plain copy

  1. public class TestLocalDateTime {  
  2.      
  3.    //6.ZonedDate、ZonedTime、ZonedDateTime : 带时区的时间或日期  
  4.    @Test  
  5.    public void test7(){  
  6.       LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));  
  7.       System.out.println(ldt);  
  8.         
  9.       ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));  
  10.       System.out.println(zdt);  
  11.    }  
  12.      
  13.    @Test  
  14.    public void test6(){  
  15.       Set<String> set = ZoneId.getAvailableZoneIds();  
  16.       set.forEach(System.out::println);  
  17.    }  
  18.   
  19.      
  20.    //5. DateTimeFormatter : 解析和格式化日期或时间  
  21.    @Test  
  22.    public void test5(){  
  23. //    DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;  
  24.         
  25.       DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");  
  26.         
  27.       LocalDateTime ldt = LocalDateTime.now();  
  28.       String strDate = ldt.format(dtf);  
  29.         
  30.       System.out.println(strDate);  
  31.         
  32.       LocalDateTime newLdt = ldt.parse(strDate, dtf);  
  33.       System.out.println(newLdt);  
  34.    }  
  35.      
  36.    //4. TemporalAdjuster : 时间校正器  
  37.    @Test  
  38.    public void test4(){  
  39.    LocalDateTime ldt = LocalDateTime.now();  
  40.       System.out.println(ldt);  
  41.         
  42.       LocalDateTime ldt2 = ldt.withDayOfMonth(10);  
  43.       System.out.println(ldt2);  
  44.         
  45.       LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));  
  46.       System.out.println(ldt3);  
  47.         
  48.       //自定义:下一个工作日  
  49.       LocalDateTime ldt5 = ldt.with((l) -> {  
  50.          LocalDateTime ldt4 = (LocalDateTime) l;  
  51.            
  52.          DayOfWeek dow = ldt4.getDayOfWeek();  
  53.            
  54.          if(dow.equals(DayOfWeek.FRIDAY)){  
  55.             return ldt4.plusDays(3);  
  56.          }else if(dow.equals(DayOfWeek.SATURDAY)){  
  57.             return ldt4.plusDays(2);  
  58.          }else{  
  59.             return ldt4.plusDays(1);  
  60.          }  
  61.       });  
  62.         
  63.       System.out.println(ldt5);  
  64.         
  65.    }  
  66.      
  67.    //3.  
  68.    //Duration : 用于计算两个“时间”间隔  
  69.    //Period : 用于计算两个“日期”间隔  
  70.    @Test  
  71.    public void test3(){  
  72.       Instant ins1 = Instant.now();  
  73.         
  74.       System.out.println("--------------------");  
  75.       try {  
  76.          Thread.sleep(1000);  
  77.       } catch (InterruptedException e) {  
  78.       }  
  79.         
  80.       Instant ins2 = Instant.now();  
  81.         
  82.       System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));  
  83.         
  84.       System.out.println("----------------------------------");  
  85.         
  86.       LocalDate ld1 = LocalDate.now();  
  87.       LocalDate ld2 = LocalDate.of(201111);  
  88.         
  89.       Period pe = Period.between(ld2, ld1);  
  90.       System.out.println(pe.getYears());  
  91.       System.out.println(pe.getMonths());  
  92.       System.out.println(pe.getDays());  
  93.    }  
  94.      
  95.    //2. Instant : 时间戳。 (使用 Unix 元年  1970年1月1日 00:00:00 所经历的毫秒值)  
  96.    @Test  
  97.    public void test2(){  
  98.       Instant ins = Instant.now();  //默认使用 UTC 时区  
  99.       System.out.println(ins);  
  100.         
  101.       OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));  
  102.       System.out.println(odt);  
  103.         
  104.       System.out.println(ins.getNano());  
  105.         
  106.       Instant ins2 = Instant.ofEpochSecond(5);  
  107.       System.out.println(ins2);  
  108.    }  
  109.      
  110.    //1. LocalDate、LocalTime、LocalDateTime  
  111.    @Test  
  112.    public void test1(){  
  113.       LocalDateTime ldt = LocalDateTime.now();  
  114.       System.out.println(ldt);  
  115.         
  116.       LocalDateTime ld2 = LocalDateTime.of(20161121101010);  
  117.       System.out.println(ld2);  
  118.         
  119.       LocalDateTime ldt3 = ld2.plusYears(20);  
  120.       System.out.println(ldt3);  
  121.         
  122.       LocalDateTime ldt4 = ld2.minusMonths(2);  
  123.       System.out.println(ldt4);  
  124.         
  125.       System.out.println(ldt.getYear());  
  126.       System.out.println(ldt.getMonthValue());  
  127.       System.out.println(ldt.getDayOfMonth());  
  128.       System.out.println(ldt.getHour());  
  129.       System.out.println(ldt.getMinute());  
  130.       System.out.println(ldt.getSecond());  
  131.    }  
  132.   
  133. }  

8.其他新特性

     Optional 容器类:用于尽量避免空指针异常

[java] view plain copy

  1. /* 
  2.  * 一、Optional 容器类:用于尽量避免空指针异常 
  3.  *     Optional.of(T t) : 创建一个 Optional 实例 
  4.  *     Optional.empty() : 创建一个空的 Optional 实例 
  5.  *     Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例 
  6.  *     isPresent() : 判断是否包含值 
  7.  *     orElse(T t) :  如果调用对象包含值,返回该值,否则返回t 
  8.  *     orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值 
  9.  *     map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty() 
  10.  *     flatMap(Function mapper):与 map 类似,要求返回值必须是Optional 
  11.  */  
  12. public class TestOptional {  
  13.      
  14.    @Test  
  15.    public void test4(){  
  16.       Optional<Employee> op = Optional.of(new Employee(101"张三"189999.99));  
  17.         
  18.       Optional<String> op2 = op.map(Employee::getName);  
  19.       System.out.println(op2.get());  
  20.         
  21.       Optional<String> op3 = op.flatMap((e) -> Optional.of(e.getName()));  
  22.       System.out.println(op3.get());  
  23.    }  
  24.      
  25.    @Test  
  26.    public void test3(){  
  27.       Optional<Employee> op = Optional.ofNullable(new Employee());  
  28.         
  29.       if(op.isPresent()){  
  30.          System.out.println(op.get());  
  31.       }  
  32.         
  33.       Employee emp = op.orElse(new Employee("张三"));  
  34.       System.out.println(emp);  
  35.         
  36.       Employee emp2 = op.orElseGet(() -> new Employee());  
  37.       System.out.println(emp2);  
  38.    }  
  39.      
  40.    @Test  
  41.    public void test2(){  
  42.       /*Optional<Employee> op = Optional.ofNullable(null); 
  43.       System.out.println(op.get());*/  
  44.         
  45. //    Optional<Employee> op = Optional.empty();  
  46. //    System.out.println(op.get());  
  47.    }  
  48.   
  49.    @Test  
  50.    public void test1(){  
  51.       Optional<Employee> op = Optional.of(new Employee());  
  52.       Employee emp = op.get();  
  53.       System.out.println(emp);  
  54.    }  
  55.      
  56.    @Test  
  57.    public void test5(){  
  58.       Man man = new Man();  
  59.         
  60.       String name = getGodnessName(man);  
  61.       System.out.println(name);  
  62.    }  
  63.      
  64.    //需求:获取一个男人心中女神的名字  
  65.    public String getGodnessName(Man man){  
  66.       if(man != null){  
  67.          Godness g = man.getGod();  
  68.            
  69.          if(g != null){  
  70.             return g.getName();  
  71.          }  
  72.       }  
  73.         
  74.       return "苍老师";  
  75.    }  
  76.      
  77.    //运用 Optional 的实体类  
  78.    @Test  
  79.    public void test6(){  
  80.       Optional<Godness> godness = Optional.ofNullable(new Godness("林志玲"));  
  81.         
  82.       Optional<NewMan> op = Optional.ofNullable(new NewMan(godness));  
  83.       String name = getGodnessName2(op);  
  84.       System.out.println(name);  
  85.    }  
  86.      
  87.    public String getGodnessName2(Optional<NewMan> man){  
  88.       return man.orElse(new NewMan())  
  89.               .getGodness()  
  90.               .orElse(new Godness("苍老师"))  
  91.               .getName();  
  92.    }  
  93. }  

     PS:若想通过代码更好的理解Java8新特性,请:https://github.com/luomingkui/java8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值