概述
- 2018年3月21日,Oracle官方宣布Java10正式发布
- 需要注意的是Java9和Java10都不是LTS(Long-term-support)版本,和过去的Java大版本升级不同,这两个只有半年左右的开发和维护期,而未来的Java11,也就是18.9LTS,才是Java8之后第一个LTS版本
- JDK10一共定义了109个新特性,其中包含12个JEP(对于程序员来讲,真正的新特性 其实就一个),还有一些新的API和JVM规范以及Java语言规范上的改动
JDK10的12个JEP(JDK Enhancement Proposal 特性加强提议) 参阅官方文档
http://openjdk.java.net/projects/jdk/10
12个JEP
Java 10 下载安装
下载
https://www.oracle.com/java/technologies/java-archive-javase10-downloads.html
安装
IDEA集成JDK10
在创建项目的时候下面会自动扫描到,点击即可选择
顺手创建个项目..这个就不截图了,应该都懂局部变量类型推断(主打功能)
产生背景
开发者经常抱怨Java中引用代码的程度,局部变量的显示类型声明,常常被认为是不必须的,给一个好听的名字经常可以很清楚的表达出下面应该怎样继续
好处
减少了啰嗦和形式的代码,避免了信息冗余,而且对齐了变量名,更容易阅读
举例如下
场景1
- 作为Java开发者, 在声明一个变量时,我们总是习惯了敲打两次变量类型,第一次用于声明变量类型,第二次用于构造器
LinkedHashSet<String> set = new LinkedHashSet<>();
- 作为Java开发者, 在声明一个变量时,我们总是习惯了敲打两次变量类型,第一次用于声明变量类型,第二次用于构造器
场景2
- 变量的声明类型书写复杂且较长,尤其是加上泛型的使用
Iterator<Map.Entry<Integer,String>> iterator = set.iterator();
- 变量的声明类型书写复杂且较长,尤其是加上泛型的使用
场景3
- 我们也经常声明一种变量,它只会被使用一次,而且是下一行代码中比如:
尽管IDE可以帮助我们自动完成这些代码,但是当变量总是跳来跳去的时候,可读性还是会受到影响,因为变量类型的名称由各种不同长度的字符组成,而且有时候开发人员会尽力避免声明中间变量,因为太多的类型名称只会分散注意力,不会带来额外的好处URL url = new URL("http://www.atguigu.com"); URLConnection urlConnection = url.openConnection();
代码(可以用)
```java // 声明变量时,根据所附的值,推断声明类型 // 我感觉就是把前端的var 拿了过来~~ 但是没有完全拿过来 var x = 10; var y = 20; System.out.println(x + y);
- 我们也经常声明一种变量,它只会被使用一次,而且是下一行代码中比如:
// 定义泛型的时候在Java8的时候可以省略右侧的,现在左侧可以变成var 那么就要在右侧,不然推断出来的是Object
var list = new ArrayList
// 遍历操作 for (var s : list) { System.out.println(s); }
for (var i = 0; i < 2; i++) { System.out.println(i); }
虽然可以用,但是我感觉谁要在项目里面写,绝对会被打死AQA
<a name="DHO2r"></a>
## 无法推断的类型
<a name="OqnA9"></a>
### 无法推断null

<a name="ZgYzU"></a>
### 无法之定义声明

<a name="enoDE"></a>
### 无法推断Lambda表达式

<a name="ZTfii"></a>
### 无法推断方法引用

<a name="zEnF5"></a>
### 无法推断显示数组

<a name="JMy77"></a>
### 其他
1. 没有初始化值
1. 值为null
1. Lambda
1. 方法引用
1. 静态初始化数组
1. 方法的返回值
1. 方法的参数列表
1. 构造器参数列表
1. 属性
1. catch块
<a name="aDJAu"></a>
## 工作原理
在处理var时,编译器先是查看表达式右边部分,并根据右边变量值的类型进行推断,作为左边的变量类型,然后将该类型写入字节码当中
<a name="HvGKJ"></a>
## 注意
<a name="kkok7"></a>
### var 不是一个关键字
你不用担心变量名或者方法名会与var冲突,因为var实际上并不是一个关键字,而是一个类型名,只有在编译器需要知道类型的地方,需要用到它,除此之外,它就是一个标准合法的标识符,也就是说除了不能用它作为类名,其他的都可以,但是极少人会用它作为类名
<a name="UIiQl"></a>
### 这不是JavaScript
首先说明的是,var并不会改变Java是一门静态类型语言的事实,编译器负责断出类型,并把结果写入字节码文件,就好像是开发人员自己敲入类型一样,下面是使用IntelliJ(实际上是Frenflower的反编译器)反编译器反编译出的代码
<a name="HAOIS"></a>
# 集合新增创建不可变集合的方法
自 Java9 开始,JDK里面的集合(List/Set/Map)都添加了of(JDK9新增)和copyOf(JDK10新增)方法,他们两个都用来创建不可变的集合,来看下他们的使用和区别
<a name="MdDT1"></a>
## 代码
```java
var list = List.of("tom", "jetty", "python");
var copy = List.copyOf(list);
System.out.println(list == copy);
var list2 = new ArrayList<>();
var copy2 = List.copyOf(list2);
System.out.println(list2 == copy2);
执行结果
true
false
为什么代码一样,结果不一样呢
因为源码中通过List.of创建的集合,他的类型是AbstractImmutableList类的子类
static <E> List<E> of(E e1, E e2, E e3) {
return new ImmutableCollections.ListN<>(e1, e2, e3);
}
然后在调用List.copyOf时,会判断是否属于这个ImmutableCollections.AbstractImmutableList
static <E> List<E> copyOf(Collection<? extends E> coll) {
if (coll instanceof ImmutableCollections.AbstractImmutableList) {
return (List<E>)coll;
} else {
return (List<E>)List.of(coll.toArray());
}
}
如果属于,会直接强制类型转换为这个泛型返回结果,其实内存地址是没有发生改变的
但是后面的通过new ArrayList
它和ArrayList是平级关系,都继承于AbstractList,这个其实就是一个只读集合,List.copyOf的方法的意思就是,如果入参是一个只读集合,那么就直接返回,如果不是,那么久创建一个只读集合返回