博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java8 新特性 详解
阅读量:7047 次
发布时间:2019-06-28

本文共 9694 字,大约阅读时间需要 32 分钟。

  hot3.png

引言:

点击--》

正题:

jdk8 的主要新特性是 主要四个:Lambda,Stream,Date,新注解,前两者主要用于集合中。

1、Lambda

主要用于匿名内部类中的一个升级版本,通常我们如果筛选一个集合的实体类的情况下,比如筛选全班星座为天秤座的学生。首先这是一个Student类

import lombok.Data;import lombok.ToString;@Data@ToStringpublic class Student {    private String name;    private String sex;    private int    salary;    private int    age;    private String star; //星座    public Student(){}    public Student(String name,String sex,int salary,int age,String star){        this.name   = name;        this.sex    = sex;        this.salary = salary;        this.age    = age;        this.star   = star;    }}

1.1 第一种方法

将这个集合遍历,然后依次的判断,这是最为普通的一种方式。

@Testpublic void test1(){    //首先创建一个    List
list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"双鱼座"), new Student("十一郎","男",3000,24,"水瓶座") ); List
result = new ArrayList<>(); for (Student student:list){ if ("天秤座".equals(student.getStar())){ result.add(student); } } System.out.println(result);}

1.2 第二种方法

通过匿名内部类的方法,在内部类中添加判断条件进行筛选。

首先创建一个公共接口:

public interface FilterProcess
{ boolean process(T t);}

接下来通过一个公共函数,对集合以及筛选条件做一个共同方法,筛选到班级里星座是天秤星座的学生

public List
filterStudent(List
students, FilterProcess
mp){ List
list = new ArrayList<>(); for (Student student : students) { if(mp.process(student)){ list.add(student); } } return list;}

最后是通过匿名内部类和该方法得到结果:

@Testpublic void test2(){    List
students = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"双鱼座"), new Student("十一郎","男",3000,24,"水瓶座") ); List
list = filterStudent(students, new FilterProcess
() { @Override public boolean process(Student student) { return student.getStar().equals("天秤座"); } }); for (Student student : list) { System.out.println(student); }}

结果如图:

170936_fVpA_3209213.png

1.3 第三种方法

但是通过这两种代码都是很多,所以java8在这一点上提供了对集合筛选最大程度的删减代码,就是第三种方法。第三种方法:通过Lambda直接判断,一步到位,不需要在写其他的方法。

@Testpublic void test3(){    List
list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"双鱼座"), new Student("十一郎","男",3000,24,"水瓶座") ); List
result = filterStudent(list,(e)->e.getStar().equals("天秤座")); System.out.println(result);}

测试结果:

[Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)]

但是现在又会有人会问这个问题,我的那个方法中是这样子的

filterStudent(List
students, FilterProcess
mp)

为什么我的代码参数却是这样子的呢

filterStudent(list,(e)->e.getStar().equals("天秤座")

来,这个跟大家好好解释,其实 -> 这个是一个连接符,左边代表参数,而右边代表 函数体(也就是我们说的条件),这个e就是代表  FilterProcess<Student> mp 这个参数的,只不过我们得java8 中lambda可以给这个参数附加上了条件,这些条件筛选都是封装到jdk8中内部类中自己实现的,所以我们只要附加条件就可以了,那个(e)就代表传了参数

总结:lambda主要是针对集合中条件的筛选,包括数组登登。接下来我们介绍Stream API ,这个和Lambda息息相关,论重要性,lambda只是基础,Stream API 才是真正的升级版

2、Stream API 详解

2.1、功能

对集合高级别的筛选,相当于sql语句中的高级查询一样,包括分页,模糊匹配登登,这是对java8 添加了 函数式编程等多功能,代码简洁,告别for循环。。。

2.2、BasicStream 是父类

子类:Stream  IntStream  LongStream  DoubleStream  不同的数据类型对应不同的接口,可以提高性能,而Stream对应的则是剩余的所有类型

2.3、Stream类型

包含两个类型,中间操作(intermediate operations)和结束操作(terminal operations)

2.4.1、Intermediate

一个Stream可以调用0到多个Intermediate类型操作,每次调用会对Stream做一定的处理,返回一个新的Stream,这类操作都是惰性化的(lazy),就是说,并没有真正开始流的遍历。 

常用操作:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel

2.4.2、Terminal

一个Stream只能执行一次terminal 操作,而且只能是最后一个操作,执行terminal操作之后,Stream就被消费掉了,并且产生一个结果。 

常用操作:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny

说下Stream,他是一个流,那什么是流呢,流是Java8引入的全新概念,它用来处理集合中的数据,暂且可以把它理解为一种高级集合。

众所周知,集合操作非常麻烦,若要对集合进行筛选、投影,需要写大量的代码,而流是以声明的形式操作集合,它就像SQL语句,我们只需告诉流需要对集合进行什么操作,它就会自动进行操作,并将执行结果交给你,无需我们自己手写代码。

因此,流的集合操作对我们来说是透明的,我们只需向流下达命令,它就会自动把我们想要的结果给我们。由于操作过程完全由Java处理,因此它可以根据当前硬件环境选择最优的方法处理,我们也无需编写复杂又容易出错的多线程代码了。

2.5 Stream 的特点

2.5.1 只能遍历一次

我们可以把流想象成一条流水线,流水线的源头是我们的数据源(一个集合),数据源中的元素依次被输送到流水线上,我们可以在流水线上对元素进行各种操作。一旦元素走到了流水线的另一头,那么这些元素就被“消费掉了”,我们无法再对这个流进行操作。当然,我们可以从数据源那里再获得一个新的流重新遍历一遍。

2.5.2 采用内部迭代方式 

若要对集合进行处理,则需我们手写处理代码,这就叫做外部迭代。而要对流进行处理,我们只需告诉流我们需要什么结果,处理过程由流自行完成,这就称为内部迭代

2.6、流的过程

2.6.1 准备一个数据源

2.6.2 执行中间操作,中间操作可以有多个,它们可以串连起来形成流水线。

2.6.3 执行终端操作,执行终端操作后本次流结束,你将获得一个执行结果。

2.7、用流来解决班级学生星座为天秤座

@Testpublic void test5(){    List
list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"双鱼座"), new Student("十一郎","男",3000,24,"水瓶座") ); list.stream() .filter((e)->e.getStar().equals("天秤座")) .forEach(System.out::println); }

这样就可以解决,当然还有很多,这只是一个条件过滤,相当于mysql 中的 where 关键词

3、JDK8 新Date

3.1 jdk7 date 的缺点

3.1.1 所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一

3.1.2 Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义

3.1.3 java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求

3.1.4 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题

3.2 jdk8 date 的优点

3.2.1 不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。

3.2.2 关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。

3.2.3 清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。

3.2.4 实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。

3.2.5 可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。

3.3 jdk8 date 新增字段含义

Java.time包中的是类是不可变且线程安全的。新的时间及日期API位于java.time中,下面是一些关键类

java8 time包下关键字段解读

属性 含义
Instant  代表的是时间戳
LocalDate  代表日期,比如2020-01-14
LocalTime  代表时刻,比如12:59:59
LocalDateTime  代表具体时间 2020-01-12 12:22:26
ZonedDateTime  代表一个包含时区的完整的日期时间,偏移量是以UTC/  格林威治时间为基准的
Period  代表时间段
ZoneOffset  代表时区偏移量,比如:+8:00
Clock  代表时钟,比如获取目前美国纽约的时间

3.4 使用jdk8 java.time下的date

3.4.1 获取当前

Instant instant = Instant.now(); //获取当前时间戳LocalDate localDate = LocalDate.now();  //获取当前日期LocalTime localTime = LocalTime.now();  //获取当前时刻LocalDateTime localDateTime = LocalDateTime.now();  //获取当前具体时间ZonedDateTime zonedDateTime = ZonedDateTime.now();   //获取带有时区的时间

3.4.2 字符串转换

jdk8:String str = "2019-01-11";DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");LocalDate localDate = LocalDate.parse(str, formatter);jdk7:SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");try {    Date date = simpleDateFormat.parse(str); } catch (ParseException e){     e.printStackTrace();}

DateTimeFormatter的包路径是java.time.formatLocalDate一样在java.time包下面,而SimpleDateFormatDate是不同的。所以当判断引入路径的时候更容易判断。

当解析失败的时候,两个异常的抛出不一样,DateTimeFormatter抛出的是DateTimeParseException,继承自RuntimeException,而ParseException明显继承的是Exception

3.4.3 Date转换LocalDate

import java.time.Instant;import java.time.LocalDate;import java.time.ZoneId;import java.util.Date;public class Test {    public static void main(String[] args) {        Date date = new Date();        Instant instant = date.toInstant();        ZoneId zoneId = ZoneId.systemDefault();        // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。        LocalDate localDate = instant.atZone(zoneId).toLocalDate();        System.out.println("Date = " + date);        System.out.println("LocalDate = " + localDate);    }}

3.4.5 LocalDate 转 Date

import java.time.LocalDate;import java.time.ZoneId;import java.time.ZonedDateTime;import java.util.Date;public class Test {    public static void main(String[] args) {        ZoneId zoneId = ZoneId.systemDefault();        LocalDate localDate = LocalDate.now();        ZonedDateTime zdt = localDate.atStartOfDay(zoneId);        Date date = Date.from(zdt.toInstant());        System.out.println("LocalDate = " + localDate);        System.out.println("Date = " + date);    }}

3.4.5 时间戳转LocalDateTime

long timestamp = System.currentTimeMillis();Instant instant = Instant.ofEpochMilli(timestamp);LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

3.4.6 LocalDateTime转时间戳

LocalDateTime dateTime = LocalDateTime.now();dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli();dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

3.4.7 LocalDate常用方法总结

getYear()    int    获取当前日期的年份getMonth()    Month    获取当前日期的月份对象getMonthValue()    int    获取当前日期是第几月getDayOfWeek()    DayOfWeek    表示该对象表示的日期是星期几getDayOfMonth()    int    表示该对象表示的日期是这个月第几天getDayOfYear()    int    表示该对象表示的日期是今年第几天withYear(int year)    LocalDate    修改当前对象的年份withMonth(int month)    LocalDate    修改当前对象的月份withDayOfMonth(intdayOfMonth)    LocalDate   修改当前对象在当月的日期isLeapYear()    boolean    是否是闰年lengthOfMonth()    int    这个月有多少天lengthOfYear()    int    该对象表示的年份有多少天(365或者366)plusYears(longyearsToAdd)    LocalDate   当前对象增加指定的年份数plusMonths(longmonthsToAdd)    LocalDate   当前对象增加指定的月份数plusWeeks(longweeksToAdd)    LocalDate   当前对象增加指定的周数plusDays(longdaysToAdd)    LocalDate   当前对象增加指定的天数minusYears(longyearsToSubtract)    LocalDate    当前对象减去指定的年数minusMonths(longmonthsToSubtract)    LocalDate    当前对象减去注定的月数minusWeeks(longweeksToSubtract)    LocalDate    当前对象减去指定的周数minusDays(longdaysToSubtract)    LocalDate    当前对象减去指定的天数compareTo(ChronoLocalDateother)    int    比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚,isBefore(ChronoLocalDateother)    boolean   比较当前对象日期是否在other对象日期之前isAfter(ChronoLocalDateother)    boolean   比较当前对象日期是否在other对象日期之后isEqual(ChronoLocalDateother)    boolean   比较两个日期对象是否相等

番外:

java8以及9的另一个讲解:--》

java8 date 更多的方法:--》

转载于:https://my.oschina.net/mdxlcj/blog/1622718

你可能感兴趣的文章
Flutter初探 上下拉分页请求+计算器实现
查看>>
Java 正则表达式详解
查看>>
你真的了解回流和重绘吗
查看>>
Coding 的回忆
查看>>
【刷算法】LeetCode.236- 二叉树的最近公共祖先
查看>>
聊聊spring cloud的HystrixAutoConfiguration
查看>>
Android字节码插桩采坑笔记
查看>>
iOS中使用Protocol Buffer
查看>>
大神解析-ZooKeeper基本原理
查看>>
网络层安全认知
查看>>
有趣的二进制2—高效位运算
查看>>
Hive 调优
查看>>
带你五步学会Vue SSR
查看>>
Angular4中自定义管道
查看>>
Android NDK开发之旅26 C++ STL
查看>>
从源码全面剖析 React 组件更新机制
查看>>
MySQL 去重SQL
查看>>
问题备忘: 服务器重启后,导致freeswitch的internal的profile无法启动
查看>>
Java虚拟机之Class类文件结构
查看>>
Service销毁流程
查看>>