-
Java8-11的变更概述
- 经过4次跳票,历经曲折的Java 9 终于终于在2017年9月21日发布。
- 从Java 9 这个版本开始,Java 的计划发布周期是6个月,下一个 Java 的主版本将于2018年3月发布,命名为 Java 18.3,紧接着再过六个月将发布 Java 18.9。
- 这意味着Java的更新从传统的以特性驱动的发布周期,转变为以时间驱动的 (6 个月为周期)发布模式,并逐步的将 Oracle JDK 原商业特性进行开源。
- 针对企业客户的需求,Oracle 将以三年为周期发布长期支持版本(long term support)。
- Java 9 提供了超过150项新功能特性,包括备受期待的模块化系统、可交互的 REPL 工具:jshell,JDK 编译工具,Java 公共 API 和私有代码,以及安全增强、扩展提升、性能管理改善等。可以说Java 9是一个庞大的系统工程, 完全做了一个整体改变。
-
Java 9新特性
新特性列举
相关资料参考
官方提供的新特性列表: https://docs.oracle.com/javase/9/whatsnew/toc.htm#JSNEW-GUIDC23AFD78-C777-460B-8ACE-58BE5EA681F
或参考 Open JDK http://openjdk.java.net/projects/jdk9/
在线Oracle JDK 9 Documentation https://docs.oracle.com/javase/9/
新特性1——接口的私有方法
概述
- Java 8中规定接口中的方法除了抽象方法之外,还可以定义静态方法和默认的方法。一定程度上,扩展了接口的功能,此时的接口更像是 一个抽象类。
- 在Java 9中,接口更加的灵活和强大,连方法的访问权限修饰符都可 以声明为private的了,此时方法将不会成为你对外暴露的API的一部分。
代码演示
定义有私有方法的接口
public interface MyInterface {
void methodShow();
static void methodStatic(){
System.out.println("接口静态方法");
}
default void methodDefault(){
System.out.println("接口的默认方法");
}
//java9之后可以在接口中定义私有方法
private void methodPrivate(){
System.out.println("接口的默认方法");
}
}
接口的实现类
public class PrivateInterfaceTest implements MyInterface{
@Override
public void methodShow() {
MyInterface.super.methodDefault();
}
@Override
public void methodDefault() {
System.out.println("实现类重写了接口中的默认方法");
}
public static void main(String[] args) {
//接口中的静态方法只能由接口自己调用
MyInterface.methodStatic();
PrivateInterfaceTest pit = new PrivateInterfaceTest();
//接口的实现类不能调用接口的静态方法
//pit.methodStatic();
pit.methodDefault();
pit.methodShow();
//接口的私有方法,不能在接口外部调用
//pit.methodPrivate();
}
}
特性2——钻石操作符使用升级
概述
- Java 7的新特性——类型推断,方便了我们在创建类的对象时,只用在前一个类后声明对应泛型即可。eg: ArrayList<String> list = new ArrayList<>();
- 但是对于匿名内部类还是不支持的,因此Java 9对应做了升级,优化了该问题。
代码演示
@Test
public void test1(){
Comparator<Integer> com = new Comparator<>() {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
};
}
新特性3——try语句改进
概述
- Java 1.8之前为了一定可以执行资源的关闭,我们需要将关闭的资源操作写在try语句的finally中
- Java 8 时,可以实现资源的自动关闭,但是要求执行后必须关闭的所有资源必须在try子句中初始化,否则编译不通过。
- Java 9 又做了写改变,用资源语句编写try将更容易,我们可以在try子句中使用已经初始 化过的资源,此时的资源是final的。
代码演示
public class Java9Test {
public static void main(String[] args) {
//Java1.8之前的写法
/*InputStreamReader isr = null;
try {
isr = new InputStreamReader(System.in);
char[] bbuf = new char[20];
int len;
if ((len = isr.read(bbuf)) != -1){
String str = new String(bbuf,0,len);
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (isr != null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}*/
//Java1.8的写法
/*try(InputStreamReader isr1 = new InputStreamReader(System.in)) {
char[] bbuf1 = new char[20];
int len;
if ((len = isr1.read(bbuf1)) != -1){
String str1 = new String(bbuf1,0,len);
System.out.println(str1);
}
}catch (IOException e){
e.printStackTrace();
}*/
//Java1.9的写法
InputStreamReader isr2 = new InputStreamReader(System.in);
OutputStreamWriter osw2 = new OutputStreamWriter(System.out);
try (isr2; osw2) {
char[] bbuf2 = new char[20];
int len;
if ((len = isr2.read(bbuf2)) != -1) {
osw2.write(bbuf2, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
新特性4——String存储结构变更
String 再也不用 char[] 来存储啦,改成了 byte[] 加上编码标记,节约 了一些空间。
新特性5——集合工厂方法:快速创建只读集合
Java8及之前创建只读集合的写法
//方式1:
@Test
public void test2(){
List<String> list = new ArrayList<>();
list.add("Jane");
list.add("Make");
list.add("Tom");
list = Collections.unmodifiableList(list);
//list.add("Jerry");//仅为可读集合,不可再次添加元素
System.out.println(list);
}
//方式2:
Set<String> set = Collections.unmodifiableSet(new HashSet<>(Arrays.asList("aa", "bb", "cc")));
set.forEach(v -> System.out.println(v));
//方式3:
Set<String> set1 = Collections.unmodifiableSet(new HashSet<String>() {
{
add("aa");
add("bb");
add("cc");
}
});
set1.forEach(v -> System.out.println(v));
通过Arrays.asList()方法得到的集合也是一个只读集合
@Test
public void test4(){
List<String> list = Arrays.asList("aa", "bb", "cc");
//list.add("dd");//不允许再次添加
list.forEach(s -> System.out.println(s));//aa bb cc
System.out.println(list);//[aa, bb, cc]
}
Java9及之后创建只读集合的写法
@Test
public void test5(){
Map<String, Integer> map = Map.of("Tom", 23, "Jane", 24, "Jerry", 25);
//map.put("Make",26);//不允许再次添加
System.out.println(map);
Map<String, Integer> map1 = Map.ofEntries(Map.entry("aa", 11), Map.entry("bb",22));
//map1.put("cc",22);//不允许再次添加
System.out.println(map1);
}
新特性6——InputStream 加强
新增:transferTo()方法,可以用来将数据直接 传输到 OutputStream,这是在处理原始数据流时非常常见的一种用法
@Test
public void test6(){
ClassLoader classLoader = this.getClass().getClassLoader();
try(InputStream is = classLoader.getResourceAsStream("day12\\data.txt");
OutputStream os = new FileOutputStream("src\\day12\\data1.txt")){
// 把输入流中的所有数据直接自动地复制到输出流中
is.transferTo(os);
}catch (IOException e){
e.printStackTrace();
}
}
新特性7——增强的 Stream API
- Java 的 Steam API 是java标准库最好的改进之一,让开发者能够快速运算, 从而能够有效的利用数据并行计算。Java 8 提供的 Steam 能够利用多核架构 实现声明式的数据处理。
- 在 Java 9 中,Stream API 变得更好,Stream 接口中添加了 4 个新的方法: takeWhile, dropWhile, ofNullable,还有个 iterate 方法的新重载方法,可以 让你提供一个 Predicate (判断条件)来指定什么时候结束迭代。
- 除了对 Stream 本身的扩展,Optional 和 Stream 之间的结合也得到了改进。 现在可以通过 Optional 的新方法 stream() 将一个 Optional 对象转换为一个 (可能是空的) Stream 对象。
新增的四个方法代码演示
- takeWhile()用于从 Stream 中获取一部分数据,接收一个 Predicate 来进行选择。在有序的 Stream 中,takeWhile 返回从开头开始的尽量多的元素。
- dropWhile()方法的行为与 takeWhile 相反,返回剩余的元素。
@Test
public void test1(){
List<Integer> list = Arrays.asList(11, 22, 12, 88, 3, 54);
//takeWhile 返回从开头开始的按照指定规则尽量多的元素
list.stream().takeWhile(s -> s < 30).forEach(System.out::println);//11 22 12
//dropWhile():与 takeWhile 相反,返回剩余的元素。
list.stream().dropWhile(s -> s < 30).forEach(System.out::println);//88 3 54
}
- ofNullable()的使用:Java 8 中 Stream 不能完全为null,否则会报空指针异常。而 Java 9 中的 ofNullable 方 法允许我们创建一个单元素 Stream,可以包含一个非空元素,也可以创建一个空 Stream。
@Test
public void test2(){
//of()参数中的多个元素,可以包含null值
Stream<? extends Serializable> stream = Stream.of(11, 22, 33, null, "ss");
stream.forEach(System.out::println);
//of()参数不能存储单个null值。否则,报异常
/*Stream<Object> stream1 = Stream.of(null);
stream1.forEach(System.out::println);*/
//Java 9新特性ofNullable():形参变量是可以为null值的单个元素
Stream<Object> stream2 = Stream.ofNullable(null);
long count = stream2.count();
System.out.println(count);//0
}
- iterate()重载的使用:这个 iterate 方法的新重载方法,可以让你提供一个 Predicate (判断条件)来指定什 么时候结束迭代。
@Test
public void test3(){
Stream.iterate(0,x -> x+1).limit(10).forEach(System.out::println);
//java9中新增的重载的方法
Stream.iterate(0,x -> x < 100,x -> x+1).forEach(System.out::println);
}
新特性8——增加Optional获取Stream的方法
Optional.stream();
@Test
public void test4(){
List<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jane");
list.add("Jerry");
Optional<List<String>> listOptional = Optional.ofNullable(list);
Stream<List<String>> stream = listOptional.stream();
//System.out.println(stream.count());//1
stream.flatMap(new Function<List<String>, Stream<?>>() {
@Override
public Stream<?> apply(List<String> list) {
return list.stream();
}
}).forEach(System.out::println);//Tom Jane Jerry
}
-
Java 10新特性
概述
- 2018年3月21日,Oracle官方宣布Java10正式发布。
- 需要注意的是 Java 9 和 Java 10 都不是 LTS (Long-Term-Support) 版本。和过去的 Java 大版本升级不同,这两个只有半年左右的开发和维护期。而之后的 Java 11,也就是 18.9 LTS,才是 Java 8 之后第一个 LTS 版本。
- JDK10一共定义了109个新特性,其中包含12个JEP(对于程序员来讲,真 正的新特性其实就一个_Local-Variable Type Inference 局部变量类型推断),还有一些新API和JVM规范以及JAVA语言规范上 的改动。
- JDK10的12个JEP(JDK Enhancement Proposal特性加强提议)参阅官方文档:http://openjdk.java.net/projects/jdk/10/
新特性1——局部变量类型推断
概述
解决的痛点
开发者经常抱怨Java中引用代码的程度。局部变量的显示类型声明,常常被认为 是不必须的,给一个好听的名字经常可以很清楚的表达出下面应该怎样继续。这样减少了啰嗦和形式的代码,避免了信息冗余,而且对齐了变量名,更容易阅读!
工作原理
在处理 var时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行推断,作为左边变量的类型,然后将该类型写入字节码当中。
注意事项
var不是一个关键字,你不需要担心变量名或方法名会与 var发生冲突,因为 var实际上并不是一个关键字, 而是一个类型名,只有在编译器需要知道类型的地方才需要用到它。除此之外,它就是一个普通合法的标识符。也就是说,除了不能用它作为类名,其他的都可以, 但极少人会用它作为类名。
这不是JavaScript,首先我要说明的是,var并不会改变Java是一门静态类型语言的事实。编译器负责推断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样。事实上,这一特性只发生在编译阶段,与运行时无关,所以对运行时的性能不会产生任何影响。所 以请放心,这不是 JavaScript。
适用于使用局部变量类型推测的创景
- 情况1:声明变量时,根据所附的值,推断变量的类型
var name = "嘻戏"; var list = new ArrayList<>();
- 情况2:遍历操作——增强for循环
var list = new ArrayList<>(); list.add("Tom"); list.add("Jerry"); for (var v : list) { System.out.println(v); }
- 情况3:遍历操作——普通for循环
for (var i = 0; i < 10; i++) { System.out.println(i); }
在局部变量中使用时,如下情况不适用
- 情况1:局部变量不赋值,就不能实现类型推断
var name;
- 情况2:lambda表示式中,左边的函数式接口不能声明为var
Consumer<String> com = (s) -> System.out.println(s); //var com1 = (s) -> System.out.println(s);
- 情况3:方法引用中,左边的函数式接口不能声明为var
Supplier<Double> sup = Math::random; //var sup1 = Math::random;
- 情况4:数组的静态初始化中,注意如下的情况也不可以
int[] arr = new int[]{11,22,33}; var arr1 = new int[]{11,22,33}; //var arr2 = {11,22,33};
在局部变量中使用时,如下结构不适用
- 情况1:没有初始化的局部变量声明
@Test public void test3(){ var num = null; }
- 情况2:方法的返回类型
public var show(String s){ return s; }
- 情况3:方法的参数类型
public void show(var s){ System.out.println(s); }
- 情况4:构造器的参数类型
public Person(var name,var id){ this.name = name; this.id = id; }
- 情况5:属性
var num;
- 情况6:catch块
try { } catch (var e) { e.printStackTrace(); }
新特性2——新增加创建只读集合方法(copyOf)
概述
自 Java 9 开始,Jdk 里面为集合(List / Set / Map)都添加了 of (jdk9新增)和 copyOf (jdk10新增)方法,它们两个都用来创建不可变的集合
copyOf(Xxx coll):如果参数coll本身就是一个只读集合,则copyOf()返回值即为当前的coll,如果参数coll不是一个只读集合,则copyOf()返回一个新的集合,这个集合是只读的。
@Test
public void test3(){
var list1 = List.of("aa","bb","cc");
var list2 = List.copyOf(list1);
System.out.println(list1 == list2);//true
var list3 = new ArrayList<String>();
List<String> list4 = List.copyOf(list3);
System.out.println(list3 == list4);//false
}
-
Java 11新特性
概述
- 2018年9 月 26 日, Oracle 官方宣布 Java 11 正式发 布。 该版本为长期支持版本(LTS, Long-Term-Support)。
- Java 11 不仅提供 了长期支持服务,还将作为 Java 平台的参考实现。 Oracle 直到2023年9月都会为 Java 11 提供技术支持,而补 丁和安全警告等扩展支持将持续到2026年。
- Java11 将带来 ZGC、 Http Client 等重要特性,一共包 含 17 个 JEP(JDK Enhancement Proposals,JDK 增强提案)。
- 从 JVM GC 的角度,JDK11 引入了两种新的 GC,其中包括也许是划时代意义 的 ZGC,虽然其目前还是实验特性,但是从能力上来看,这是 JDK 的一个巨大突破,为特定生产环境的苛刻需求提供了一个可能的选择。例如,对部分企业核心存储等产品,如果能够保证不超过 10ms 的 GC 暂停,可靠性会 上一个大的台阶,这是过去我们进行 GC 调优几乎做不到的,是能与不能的问题。
新特性1:String中新增的方法
- isBlank():判断字符串是否为空白
System.out.println("".isBlank());//true System.out.println("\n".isBlank());//true System.out.println("\t".isBlank());//true
- strip():去除首尾空白
- stripTrailing():去除尾部空格
- stripLeading():去除首部空格
String str = " ***" + " \t abc \t " + "*** "; System.out.println(str);// *** abc *** System.out.println(str.strip());//*** abc *** System.out.println(str.trim());//*** abc *** System.out.println(str.stripTrailing());// *** abc *** System.out.println(str.stripLeading());//*** abc ***
- repeat(int count):复制字符串
String s = "ab"; System.out.println(s.repeat(3));//ababab
- lines().count():行数统计
String s1 = "ab\n11\n"; String s2 = "ab\n11\n22"; System.out.println(s1.lines().count());//2 System.out.println(s2.lines().count());//3
新特性2:Optional新增的方法
Optional 也增加了几个非常酷的方法,现在可以很方便的将一个 Optional 转换 成一个 Stream, 或者当一个空 Optional 时给它一个替代的。
- boolean isEmpty() 判断value是否为空 (JDK 11新增)
Optional<Object> empty = Optional.empty(); System.out.println(empty.isEmpty());//true //判断内部的value是否为空(Java11新增方法) System.out.println(empty.isPresent());//false //判断内部的value是否存在
- T orElseThrow() value非空,返回value;否则抛异常 NoSuchElementException(JDK 10新增)
var optional = Optional.of("aaa"); String s = optional.orElseThrow(); System.out.println(s);
- ifPresentOrElse(Consumer action, Runnable emptyAction) value非空,执行参数1功能;如果value 为空,执行参数2功能(JDK 9新增)
@Test public void test4(){ Optional<String> optional = Optional.of("111");//非空执行参数1的功能 //Optional<Object> optional = Optional.empty();空执行参数2的功能 Optional<String> optional1 = Optional.of("aaa"); Optional<String> optional2 = Optional.of("bbb"); optional.ifPresentOrElse((s) -> System.out.println(optional1),() -> System.out.println(optional2)); }
- Optional or(Supplier> supplier) value非空,返回对应的Optional; value为空,返回形参封装的Optional(JDK 9新增)
@Test public void test3(){ var optional = Optional.of("aaa"); var optional1 = Optional.of("bbb"); Optional<String> or = optional.or(() -> optional1); System.out.println(or);//Optional[aaa] var optional2 = Optional.empty(); var optional3 = Optional.of("bbb"); Optional<Object> or1 = optional2.or(() -> optional3); System.out.println(or1);//Optional[bbb] }
新特性3:局部变量类型推断的升级
在var上添加注解的语法格式,在jdk10中是不能实现的。在JDK11中加入了这样的语法。
//使用var的好处是在使用lambda表达式时给参数加上注解。
Consumer com = (@MyAnnotation var t) -> System.out.println(t.getClass());