目录
Java8(又称为 jdk 1.8) 是 Java 语言开发迄今为止的一个最主要和用户最多的一个版本。Java8是Oracle公司于2014年3月18日发布 ,它不仅支持函数式编程,而且还拥有新的日期 API,Stream API 等操作。
1.Lambda表达式
Lambda 允许把函数作为一个方法的参数,使用Lambda表达式可以使代码变的更加简洁紧凑、简洁表达。
lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值((x1,x2))。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果函数主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回一个数值。
- lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义,详细见如下案例)
lambda表达式的语法:
(parameters) -> expression 或 (parameters) ->{ statements; } (x)->{system.out.prinln} //直接打印x参数;
lambda表达式简单例子:
/** * lambda * */ public class Java8TestLambda { public static void main(String [] args){ CacualtePriceService cacualteAddPriceService=(x1,x2)->(x1+x2); CacualtePriceService cacualteSubPriceService=(x1,x2)->(x1-x2) System.out.println(cacualteAddPriceService.cacluatePrice(1.2f,2.2f));//3.4 System.out.println(cacualteSubPriceService.cacluatePrice(3.2f,1.2f));//2.0 System.out.println("------------------使用策略模式----------------------"); System.out.println(operate(1.2f,2.2f,(x1,x2)->(x1+x2)));//3.4 System.out.println(operate(3.2f,1.2f,(x1,x2)->(x1-x2)));//2.0 } /** * 计算价格接口 */ interface CacualtePriceService{ Float cacluatePrice(Float x1,Float x3); } static Float operate(float x1, float x2, CacualtePriceService cacualtePriceService){ return cacualtePriceService.cacluatePrice(x1,x2); } }
打印结果:
3.4 2.0 ------------------使用策略模式---------------------- 3.4 2.0
由上面的例子可知,Lambda可以简化函数接口(接口中只有一个方法,例如上述例子中CacualtePriceService接口)的实现方法。
// static final float num=1.1f; public static void main(String [] args){ float num=1.1f; CacualtePriceService cacualteAddPriceService=(x1,x2)->(x1+x2+num); CacualtePriceService cacualteSubPriceService=(x1,x2)->(x1-x2+num); num=2; } console://当修改num=2 时候会报错: Error:(14, 70) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
当修改num=2 时候会报错:从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量。
2.添加默认方法
java 8添加了接口的默认方法,简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现的方法。
我们只需在方法名前面加个 default 关键字即为默认方法。
为什么要有这个特性?
之前的接口,当需要修改接口时候,需要修改全部实现该接口的类,然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法,目的是为了解决接口的修改与现有的实现不兼容的问题。
默认方法案例如下:
/** * jdk 1.8 默认方法 */ public class DafaultMethod { interface Car { static void staticRun() { System.out.println("测试汽车静态接口"); } default void defaultRun() { System.out.println("测试汽车默认接口"); } void run(); } static class QicheCar implements Car { @Override public void run() { System.out.println("测试汽车实现接口"); defaultRun(); Car.staticRun(); } } public static void main(String[] args) { QicheCar car = new QicheCar(); car.run(); } }
输出内容:
测试汽车实现接口 测试汽车默认接口 测试汽车静态接口
由上述案例可知,接口直接可以调用静态方法以及默认方法。
3.Stream操作
要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选,排序,聚合等操作。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。Java中的Stream并不会存储元素,而是按需计算。
数据源中流的来源 可以是集合,数组,I/O channel, 产生器generator 等。
(1)Stream基本操作
一、获取流
1.1 所有的 Collection 集合都可以通过 stream 默认方法获取流
1.2 Stream 接口的静态方法 of 可以获取数组对应的流。
二、中间操作
1.过滤 filter
2.去重 distinct
3.排序 sorted
4.截取 limit
5.跳跃 skip
6.转换map/flatMap
7.其他 peek
三、终止操作
1、循环 forEach
2、计算 min、max、count、 average
3、匹配 anyMatch、 allMatch、 noneMatch、findFirst、 findAny
4、汇聚 reduce
5、收集器 toArray collect
4.Optional 类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
5.Java时间API
Java 8 在 java.time 包下提供了很多新的 API 。两个比较重要的 API:Local(本地) − 简化了日期时间的处理,没有时区的问题。Zoned(时区) − 通过制定的时区处理日期时间。
具体案例参考如下:
public void testLocalDateTime(){ // 获取当前时间 LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt);//2021-06-29T16:27:58.543 // 获取指定时间 LocalDateTime ld2 = LocalDateTime.of(2016, 11, 21, 10, 10, 10); System.out.println(ld2);//2016-11-21T10:10:10 // 指定时间后移动2年 LocalDateTime ldt3 = ld2.plusYears(20); System.out.println(ldt3);//2036-11-21T10:10:10 // 指定时间前移动2月 LocalDateTime ldt4 = ld2.minusMonths(2); System.out.println(ldt4);//2016-09-21T10:10:10 System.out.println(ldt.getYear());//2021 System.out.println(ldt.getMonthValue());//6 System.out.println(ldt.getDayOfMonth());//29 System.out.println(ldt.getHour());//16 System.out.println(ldt.getMinute());//27 System.out.println(ldt.getSecond());//58 System.out.println("---------------当前时间解析-------------------"); // 当前时间解析 LocalDateTime currentTime = LocalDateTime.now(); System.out.println("当前时间: " + currentTime);//2021-06-29T16:27:58.546 LocalDate date1 = currentTime.toLocalDate(); System.out.println("date1: " + date1);// 2021-06-29 Month month = currentTime.getMonth(); Integer mon=month.ordinal()+1; int day = currentTime.getDayOfMonth(); int seconds = currentTime.getSecond(); System.out.println("月: " + month +"/"+mon+", 日: " + day +", 秒: " + seconds);//月: JUNE/6, 日: 29, 秒: 58 LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012); System.out.println("date2: " + date2);//date2: 2012-06-10T16:27:58.546 // 12 december 2014 LocalDate date3 = LocalDate.of(2014, Month.FEBRUARY, 25); System.out.println("date3: " + date3);//date3: 2014-02-25 // 22 小时 15 分钟 LocalTime date4 = LocalTime.of(22, 15); System.out.println("date4: " + date4);//date4: 22:15 // 解析字符串 LocalTime date5 = LocalTime.parse("20:15:30"); System.out.println("date5: " + date5);//date5: 20:15:30 System.out.println("-------------Instant : 时间戳--------------------"); // Instant : 时间戳。 (使用 Unix 元年 1970年1月1日 00:00:00 所经历的毫秒值) Instant ins = Instant.now(); //默认使用 UTC 时区 比大陆时间提前8小时 System.out.println("ins"+ins);//ins2021-06-29T08:27:58.578Z OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8)); System.out.println("odt"+odt);//odt2021-06-29T16:27:58.578+08:00 System.out.println("ins.getNano():"+ins.getNano());//ins.getNano():578000000 Instant ins2 = Instant.ofEpochSecond(5); System.out.println("ins2:"+ins2);//ins2:1970-01-01T00:00:05Z System.out.println("----------耗费时间统计------------"); Instant ins1 = Instant.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { } Instant ins3 = Instant.now(); System.out.println("所耗费时间为:" + Duration.between(ins1, ins3));//所耗费时间为:PT1.005S LocalDate ld3 = LocalDate.now(); LocalDate ld4 = LocalDate.of(2011, 1, 1); Period pe = Period.between(ld4, ld3); System.out.println(pe.getYears());//10 System.out.println(pe.getMonths());//5 System.out.println(pe.getDays());//28 }