jdk1.8新特性总结

Posted zhangpeng8888

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk1.8新特性总结相关的知识,希望对你有一定的参考价值。

一、Lambda表达式

什么是Lambda表达式

Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。

lambda表达式本质上是一段匿名内部类,也可以是一段可以传递的代码。

为什么要用?

lambda是一个匿名函数,我们可以把lambda理解为一个可以传递的代码(将代码像数据一样传递),可以写出更简洁更灵活的代码,增强了代码的可读性。

lambda 的结构

a)       一个 Lambda 表达式可以有零个或多个参数

b)       参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)与(a)效果相同

c)        所有参数需包含在圆括号内,参数之间用逗号相隔。例如:(a, b) 或 (int a, int b) 或 (String a, int b, float c)

d)       空圆括号代表参数集为空。例如:() -> 42

e)       当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a

f)         Lambda 表达式的主体可包含零条或多条语句

g)       如果 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致

h)       如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空

技术图片

 

 

 

方法引用

若lambda体中的内容有方法已经实现了,那么可以使用“方法引用” ,也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单

(a) 方法引用

三种表现形式:

  1. 对象::实例方法名

例如:Consumer<Integer> con = System.out::println;

  1. 类::静态方法名

例如:BiFunction<Integer, Integer, Integer> biFun = Integer::compare;

  1. 类::实例方法名 (lambda参数列表中第一个参数是实例方法的调用者,第二个参数是实例方法的参数时可用)

例如:BiFunction<String, String, Boolean> fun = String::equals;

(b)构造器引用

格式:ClassName::new

例如:Function<Integer, Employee> fun = Employee::new;

(c)数组引用

格式:Type[]::new

例如:Function<Integer, String[]> fun = String[]::new;

lambda使用举例:

 1     /**
 2      * 1.ArrayList的使用
 3      */
 4     @Test
 5     public  void test1(){
 6         //传统方式
 7         Integer[] numArr= {1,6,3,2,4,5,7};
 8         List<Integer> list = Arrays.asList(numArr);
 9         for (Integer num:numArr){
10             System.out.println("===>"+num);
11         }
12 
13         //lambda方式
14         list.forEach((num)->{System.out.println("===>"+num); });
15         System.out.println("-----------------------");
16 
17     }
18 
19     /**
20      * 2.Runnable(线程)的使用
21      */
22     @Test
23     public void test2(){
24         //使用匿名内部类
25         new Runnable(){
26             @Override
27             public void run() {
28                 System.out.println("hello word!");
29             }
30         }.run();
31         //使用lambda表达式
32         Runnable runnable = ()-> System.out.println("hello word!");
33         System.out.println("-----------------------");
34     }
35 
36     /**
37      * 3.Thread(线程的使用)
38      */
39     @Test
40     public void test3(){
41         //使用匿名内部类
42         new Thread(new Runnable(){
43             @Override
44             public void run() {
45                 System.out.println("hello word!");
46             }
47         }).start();
48         //使用lambda表达式
49         new Thread(()-> System.out.println("hello word"));
50         System.out.println("-----------------------");
51     }
52     /**
53      * 4.sort排序
54      */
55     @Test
56     public void test4(){
57         //正常情况使用排序
58         String[] player = {"aa","cc","bb","ee","dd","gg","ff"};
59         Arrays.sort(player, new Comparator<String>() {
60             @Override
61             public int compare(String o1, String o2) {
62                 return o1.compareTo(o2);
63             }
64             public String compare1(String o1, String o2) {
65                 return o1;
66             }
67         });
68         Arrays.asList(player).forEach(e-> System.out.println("==>"+e));
69 
70         //lambda表达式
71         //方式1
72         Comparator<String> comparator = (o1,o2)-> (
73             o1.compareTo(o2)
74 
75         );
76         Arrays.sort(player,comparator);
77         Arrays.asList(player).forEach(e-> System.out.println("==>"+e));
78         //方式2
79         Arrays.sort(player,(String o1,String o2)->(o1.compareTo(o2)));
80         Arrays.asList(player).forEach(e-> System.out.println("==>"+e));
81     }

 

二、Stream流

定义:

流是Java API的新成员,它允许我们以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。就现在来说,我们可以把它们看成遍历数据集的高级迭代器。此外,流还可以透明地并行处理,也就是说我们不用写多线程代码了。

  Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。

  Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。

  对stream的操作可以分为两类,中间操作(intermediate operations)和结束操作(terminal operations):

中间操作总是会惰式执行,调用中间操作只会生成一个标记了该操作的新stream。

      结束操作会触发实际计算,计算发生时会把所有中间操作积攒的操作以pipeline的方式执行,这样可以减少迭代次数。计算完成之后stream就会失效。

// 1. Individual values

Stream stream = Stream.of("a", "b", "c");

// 2. Arrays

String [] strArray = new String[] {"a", "b", "c"};

stream = Stream.of(strArray);

stream = Arrays.stream(strArray);

// 3. Collections

List<String> list = Arrays.asList(strArray);

stream = list.stream();

 

Stream操作的三个步骤

创建stream:一个数据源(如:集合、数组),获取一个流

中间操作(过滤、map):一个中间操作链,对数据源的数据进行处理

终止操作:一个终止操作,执行中间操作链,并产生结果

stream的创建:

    // 1,校验通过Collection 系列集合提供的stream()或者paralleStream()

    List<String> list = new ArrayList<>();

    Strean<String> stream1 = list.stream();

 

    // 2.通过Arrays的静态方法stream()获取数组流

    String[] str = new String[10];

    Stream<String> stream2 = Arrays.stream(str);

 

    // 3.通过Stream类中的静态方法of

    Stream<String> stream3 = Stream.of("aa","bb","cc");

 

Stream的中间操作:

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。

 技术图片

技术图片

 技术图片

Stream的终止操作:

终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。

 技术图片

 技术图片

 技术图片

 技术图片

 stream使用测试

  1 /**
  2      * Stream操作
  3      */
  4     @Test
  5     public void test5(){
  6         /**
  7          * Stream创建
  8          */
  9         String[] arr = {"1","3","2","4"};
 10         //通过Stream类中的静态方法of
 11         Stream stream1 = Stream.of("1","3","2","4");
 12         //通过Arrays的静态方法stream()获取数组流
 13         Stream stream2 = Arrays.stream(arr);
 14         //通过Collection 系列集合提供的stream()
 15         Stream stream3 = Arrays.asList(arr).stream();
 19     }
 22 
 23     @Test  public void testForEach(){
 24         List<User> list = Arrays.asList(
 25                 new User("张三", 11),
 26                 new User("王九", 20),
 27                 new User("王五", 91),
 28                 new User("张三", 8),
 29                 new User("李四", 44),
 30                 new User("陆二狗", 43),
 31                 new User("刘大麻子", 49)  );
 32         /**
 33          *  forEach 迭代输出每条数据.
 34          */
 35         // java 8 前
 36         System.out.println("java 8 前");
 37         for(User user: list){
 38             System.out.println(user);
 39         }
 40         // java 8 lambda
 41         System.out.println("java 8 lambda");
 42         list.forEach(user -> System.out.println(user));
 43         // java 8 stream lambda
 44          System.out.println("java 8 stream lambda");
 45          list.stream().forEach(user -> System.out.println(user));
 46         System.out.println("-------------------");
 47          //筛选过滤去重
 48         list.stream().filter(e->e.getAge()>11).limit(3).forEach(user -> System.out.println(user));
 49     }
 50     /**   * sort 排序.   */
 51     @Test  public void testSort() {
 52         List<User> list = Arrays.asList(
 53                 new User("张三", 11),
 54                 new User("王九", 20),
 55                 new User("王五", 91),
 56                 new User("张三", 8),
 57                 new User("李四", 44),
 58                 new User("陆二狗", 43),
 59                 new User("刘大麻子", 49)  );
 60         System.out.println("-----排序前-----");
 61         list.forEach(user -> System.out.println(user));
 62         System.out.println("-----排序后-----");
 63         // java 8 前
 64         System.out.println("java 8 前");
 65        Collections.sort(list, new Comparator<User>() {
 66             @Override
 67             public int compare(User o1, User o2) {
 68                 return String.valueOf(o1.getAge()).compareTo(String.valueOf(o2.getAge()));
 69             }
 70        });
 71        for (User user : list) {
 72            System.out.println(user);
 73        }
 74         //java 8 stream 方法引用
 75         System.out.println("java 8 stream 方法引用");
 76         list.stream().sorted(Comparator.comparing(user -> user.getAge())).
 77         forEach(user -> System.out.println(user));
 78        }
 79 
 80     /**   * filter 过滤.   */
 81     @Test  public void testFilter() {
 82         List<User> list = Arrays.asList(
 83                 new User("张三", 11),
 84                 new User("王九", 20),
 85                 new User("王五", 91),
 86                 new User("张三", 8),
 87                 new User("李四", 44),
 88                 new User("陆二狗", 43),
 89                 new User("刘大麻子", 49)  );
 90         System.out.println("-----排序前-----");
 91         // 输出年龄大于50的人
 92          System.out.println("-----过滤前-----");
 93          list.forEach(user -> System.out.println(user));
 94          System.out.println("-----过滤后-----");
 95          //java 8 前
 96          System.out.println("java 8 前");
 97          for(User user: list){
 98             if (user.getAge() > 50) {
 99                 System.out.println(user);
100             }
101          }
102          //java 8 stream
103          System.out.println("java 8 stream");
104          list.stream().filter((User user) -> user.getAge() > 50).
105          forEach(user -> System.out.println(user));
106     }
107     /**   * map 映射.   */
108     @Test  public void testMap() {
109         List<User> list = Arrays.asList(
110                 new User("张三", 11),
111                 new User("王九", 20),
112                 new User("王五", 91),
113                 new User("张三", 8),
114                 new User("李四", 44),
115                 new User("陆二狗", 43),
116                 new User("刘大麻子", 49)  );
117         // 只输出所有人的年龄
118         list.stream().forEach(user -> System.out.println(user));
119         System.out.println("映射后------>");
120 
121         List<Integer> ages = list.stream().map(user -> user.getAge()).collect(Collectors.toList());
122         ages.forEach(age -> System.out.println(age));
123         // 小写转大写
124          List<String> words = Arrays.asList("aaa", "vvvv", "cccc");
125          System.out.println("全部大写---->");
126          List<String> collect = words.stream().map(s -> s.toUpperCase()).collect(Collectors.toList());
127         collect.forEach(s -> System.out.println(s));
128     }

 

三、新的日期API

1.8之前JDK自带的日期处理类非常不方便,我们处理的时候经常是使用的第三方工具包,比如commons-lang包等。不过1.8出现之后这个改观了很多,比如日期时间的创建、比较、调整、格式化、时间间隔等。这些类都在java.time包下。比原来实用了很多。

新的日期API好处:

* 之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便,java.time.LocalDate月份和星期都改成了enum

 * java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime和最基本的String一样,是不变类型,不但线程安全,而且不能修改。

 * java.util.Date是一个“万能接口”,它包含日期、时间,还有毫秒数,更加明确需求取舍

 * 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对

 

LocalDate/LocalTime/LocalDateTime

  LocalDate为日期处理类、LocalTime为时间处理类、LocalDateTime为日期时间处理类,方法都类似,具体可以看API文档或源码,选取几个代表性的方法做下介绍。

now相关的方法可以获取当前日期或时间,of方法可以创建对应的日期或时间,parse方法可以解析日期或时间,get方法可以获取日期或时间信息,with方法可以设置日期或时间信息,plus或minus方法可以增减日期或时间信息;

TemporalAdjusters

   这个类在日期调整时非常有用,比如得到当月的第一天、最后一天,当年的第一天、最后一天,下一周或前一周的某天等。

DateTimeFormatter

以前日期格式化一般用SimpleDateFormat类,但是不怎么好用,现在1.8引入了DateTimeFormatter类,默认定义了很多常量格式(ISO打头的),在使用的时候一般配合LocalDate/LocalTime/LocalDateTime使用,比如想把当前日期格式化成yyyy-MM-dd hh:mm:ss的形式:

 1 /**
 2      * 时间处理api
 3      */
 4     @Test
 5     public void testDate(){
 6         //当前时间
 7         LocalDate now = LocalDate.now();
 8         System.out.println("当前时间:"+now);
 9 
10         //前一天时间
11         LocalDate yesterday = now.minusDays(1);
12         System.out.println("昨天:"+yesterday);
13         //上个月
14         LocalDate lastMonth = now.minusMonths(1);
15         System.out.println("上个月:"+lastMonth);
16         //上一周
17         LocalDate lastWeek = now.minusWeeks(1);
18         System.out.println("上一周:"+lastWeek);
19         //一周后
20         LocalDate nextWeek = now.plusWeeks(1);
21         System.out.println("一周后:"+nextWeek);
22         //指定日期
23         LocalDate ofDate = LocalDate.of(2020, 4, 7);
24         System.out.println("指定日期:"+ofDate);
25         //转换日期对象
26         LocalDate parseDate = LocalDate.parse("2020-04-09");
27         System.out.println("转换日期对象:"+parseDate);
28         // 取本月第1天:
29         LocalDate firstDayOfThisMonth = now.with(TemporalAdjusters.firstDayOfMonth());
30         LocalDate firstDayOfThisMonth1 = now.withDayOfMonth(1);
31         System.out.println("本月第一天:"+firstDayOfThisMonth);
32         System.out.println("本月第一天1:"+firstDayOfThisMonth1);
33         // 取本月第2天:
34         LocalDate secondDayOfThisMonth = now.withDayOfMonth(2);
35         System.out.println("本月第二天:"+secondDayOfThisMonth);
36         // 取本月最后一天,再也不用计算是28,29,30还是31:
37         LocalDate lastDayOfThisMonth = now.with(TemporalAdjusters.lastDayOfMonth());
38         System.out.println("本月最后一天:"+lastDayOfThisMonth);
39         //获取当前月份,得到结果不用加1
40         int month = now.getMonthValue();
41         System.out.println("当前月份:"+month);
42         int dayOfYear = now.getDayOfYear();
43         System.out.println("2020年已经度过的天数:"+dayOfYear);
44         LocalDateTime nowTime = LocalDateTime.now();
45         String formatDate = DateTimeFormatter.ISO_LOCAL_DATE.format(nowTime);
46         System.out.println("formatDate:"+formatDate);
47         DateTimeFormatter formatter =DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
48         String formatDateTime = formatter.format(nowTime);
49         System.out.println("formatDateTime:"+formatDateTime);
50         DateTimeFormatter formatter1 =DateTimeFormatter.ofPattern("YYYY/MM/dd HH:mm:ss");
51         String formatDateTime1 = formatter1.format(nowTime);
52         System.out.println("formatDateTime1:"+formatDateTime1);
53     }

运行结果:

技术图片

 

以上是关于jdk1.8新特性总结的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8新特性Stream和Collectors19个常用示例总结

JDK1.8新特性

jdk1.8新特性——主要内容

JAVA 8 主要新特性 ----------------JDK1.8优点概括

JDK1.8新特性

Java8(JDK1.8)新特性