jdk1.8特性总结
目录-jdk1.8特性大纲总结
jdk1.8特性大纲总结(便于回忆记录)
jdk1.8是2014年3月18日正式公布,公司的开发项目也都逐渐的开始使用jdk1.8作为开发的基础版本;我个人是比较喜欢jdk1.8的编码风格:
优点:
- lambda表达式的方式有点类似于scala的编程风格,能够让代码简洁
- optional 快速的定位到NPE(Null Pointer Exception),个人感觉在开发需求中所写的代码中有大部分都是各种异常的判断和空指针的处理逻辑,真实的业务代码部分实际上不多,所以1.8中的这个optional如果能够使用得当的话,可以避免很多的空指针,同时能够使代码更加的简洁
缺点:
- 函数式编程的风格也同时会带来代码的不易读的缺点。
(一)Lambda表达式
1. 函数式编程
1)闭包和高阶函数
闭包:
闭包是一个比较特殊的函数,下面两种说法是比较多的定义:
- 闭包是在其上下文中引用了*变量的函数
- 闭包是有由函数和其相关的引用环境组合而成的实体
闭包反应是的是一个开发到封闭的过程;
函数可以在变量不再处于作用域内时被调用。这样的函数称为闭包;而定义一个闭包函数是将这个*变量捕获而构成的一个封闭的函数;
提到闭包,想要了解的同学可以了解下柯里化;
高阶函数:
对于高阶函数,比较官方的解释是:高阶函数可以用另一个函数(间接地,用一个表达式) 作为其输入参数,在某些情况下,它甚至返回一个函数作为其输出参数。这两种结构结合在一起使得可以用优雅的方式进行模块化编程,这是使用 FP 的最大好处。
FP(Function Programming)
个人理解,就是将函数作为参数,可以将函数作为返回值,例如f(*) 是一个函数,高阶函数的f(f(f(x)))将函数当成参数放入到函数中;
2)immutable data 不可变数据
默认变量的值是不可变的
3)函数式一等公民 first class functions
可以将函数作为变量一样来使用
4)惰性计算
表达式不是在绑定的时候进行计算的,而是在需要产生值得时候才开始计算;避免计算过程中的值占用过多的内存,从而造成out-of-memory的问题
5)尾递归优化
如果递归很深的话,stack受不了,并会导致性能大幅度下降。使用尾递归优化技术——每次递归时都会重用stack,这样能够提升性能,需要语言或编译器的支持。
当然这里要顺便说一句,函数式编程的主要编程语言代表是scala,所以想要学习详细的函数式编程的可以学习下scala语言,这也是spark技术的底层语言;
2. lambda表达式
1)lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值
2)语法:
lambda 表达式的语法格式如下:
(x) -> 表达式
或
(x1, x2, x3 ... ...) ->{ 可执行表达式; }
3)例子:
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
(二) 函数式接口
(1)定义: 接口并且仅有一个抽象方法
(2)SAM接口:Single Abstract Method interfaces
(3)特点:
- 有且仅有一个抽象方法
- 允许定义静态方法
- 允许定义默认方法
- 允许java.lang.Object 中的public方法
- @FuncationalInterface 标注 标记函数式接口,但不是必须的,加上可以更好的让编译器检查,当然也可以不使用,但是如果使用了,接口不符合函数式接口,编译器会报错
(4)常用接口:
Consumer<T> : 消费型接口,有参无返回值
Supplier<T> : 供给型接口,无参有返回值
Funciton<T, R> : 函数型接口,有参有返回值
Predicate<T> : 断言型接口,有参有返回值, 返回值是boolean类型
(三)方法引用
1. 方法引用
主要有三种表现形式:
1)对象:: 实例方法名
2)类:: 静态方法名
3)类:: 实例方法名(第一个参数实例方法的调用者, 第二个参数实例方法的参数时可用)
2. 构造器引用
格式:Classname::new
3. 数组引用
格式: Type[] :: new
(三)Stream API
1. stream流
Stream流是一个来自数据源的元素队列并支持聚合(aggregate)操作;
(聚合操作个人理解主要是将数据集中的数据按照某种规则进行汇总合并成一个或者多个数据集合的过程)
- 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
- 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
- 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
和以前的Collection操作不同,
Stream操作还有两个基础的特征:
- Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
- 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。
2.生成流
集合接口有两种方法生成流:
(1)stream 为集合创建串行流
(2)parallelStream()为集合创建并行流
代码示例:(仅供参考)
List<Integer> arrayList = Arrays.asList(1, 2, 2, 4, 5);
boolean b = arrayList.stream().anyMatch(x -> x > 3);
out.println("any num > 3 is " + b);
boolean b1 = arrayList.stream().allMatch(x -> { return x > 3; });
out.println("all num > 3 is " + b1);
List<Integer> collect = arrayList.stream().map(x -> x + 3).collect(Collectors.toList());
collect.forEach(out::println);
List<String> list = Arrays.asList();
list.stream().forEach(out::println);
List<String> collect1 = list.stream().map(x -> x + "test").collect(Collectors.toList());
collect1.stream().forEach(out::println);
运行结果
any num > 3 is true
all num > 3 is false
4
5
5
7
8
(四)并行流和串行流
并行流把内容切割成多个数据块, 并且使用多个线程分别处理每个数据块的内容
通过parallel()和sequential() 方法在并和串行流间切换
jdk1.8并行流使用forkJoin框架并行操作
(五)Optional容器
快速定位NPE, 一定程度上减少非空校验的代码量
(六)时间函数
LocalDate 、LocalTime 、LocalDateTime
LocalDate 只能操作当前时间的年月日
LocalTime 操作当前时间的时分秒
LocalDateTime 操作年月日时分秒
均可使用静态方法now()和静态方法of()来创建对象
简单例子:
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
LocalDateTime of = LocalDateTime.of(localDate, localTime);
System.out.println(of);
LocalDateTime of1 = LocalDateTime.of(2020, 02, 02, 21, 23, 02);
System.out.println(of1);
运行结果:
2020-07-29
10:00:10.684
2020-07-29T10:00:10.684
2020-07-29T10:00:10.684
2020-02-02T21:23:02
这里指的提的一句是,java1.8中的DateTimeFormatter日期格式化的工具, 在java1.8中DateTimeFormatter是线程安全的,LocalDateTime,DateTimeFormatter两个类都没有线程问题,只要你自己不把它们创建为共享变量就没有线程问题。
可以使用Instant代替 Date,LocalDateTime代替 Calendar,DateTimeFormatter 代替 SimpleDateFormat。
注意:SimpleDateFormat是非线程安全的,使用的时候需要注意线程不安全的解决
(1)将SimpleDateFormat设置为局部变量
(2)对使用simpleDateFormat实例的地方加上线程同步锁,synchronized(lock)
(3)使用ThreadLocal,对每个线程拥有自己的simpleDateFormat对象副本
(七)java8脚本引擎 Nashorn
Nashorn 扩展Java在JVM上运行动态JavaScript脚本的能力。
(八)java1.8目录结构
- bin目录: 命令行开发和调试工具 javac jar 和javadoc
- include目录:编译本地代码时使用的c/c++文件
- lib目录:jdk工具的几个jar, 和其他类型的文件;有一个tools.js其中包含javac编译器的java类
- jre/lib目录:基本命令;windows平台上,包含系统改的运行是动态链接库DLL
- jre/lib目录:用户可编辑的配置文件, rt.jar文件包含运行时的java类和资源文件
(九)参考
- https://www.cnblogs.com/shihaiming/p/11082154.html
- https://www.runoob.com/java/java8-lambda-expressions.html
本文地址:https://blog.csdn.net/u014112521/article/details/107646648