1.局部变量类型推断
-
var javastack = "javastack";
-
System.out.println(javastack);
大家看出来了,局部变量类型推断就是左边的类型直接使用 var
定义,而不用写具体的类型,编译器能根据右边的表达式自动推断类型,如上面的 String
。
-
var javastack = "javastack";
就等于:
-
String javastack = "javastack";
局部变量类型推断使用示例
既然叫局部变量类型推断,以只能用在局部变量中,下面给出更多使用示例。
1、字面量定义局部变量
-
private static void testVar() {
-
var javastack = "javastack";
-
System.out.println(javastack);
-
}
2、接收方法返回值定义局部变量
-
private static void testMethod() {
-
var javastack = getJavastack();
-
System.out.println(javastack);
-
}
-
public static String getJavastack() {
-
return "javastack";
-
}
3、循环中定义局部变量
-
private static void testLoop() {
-
for (var i = 0; i < 3; i++) {
-
for (var m = 10; m < 15; m++) {
-
System.out.println(i + m);
-
}
-
}
-
}
4、泛型结合局部变量
-
private static void testGeneric() {
-
// 表达式1
-
List<String> list1 = new ArrayList<>();
-
list1.add("javastack");
-
// 表达式2
-
var list2 = new ArrayList<>();
-
list2.add(2018);
-
// 表达式3
-
var list3 = new ArrayList<String>();
-
list3.add("javastack");
-
}
表达式1后面 <>
里面 jdk 1.7+开始是不用带具体类型的,在接口中指明就行了。
表达式2中如果使用 var
的话, <>
里面默认会是 Object
的,所以可以添加任意类型。
表达式3中在 <>
强制使用了 String 来指定泛型。
局部变量类型推断不能用在以下场景
1、类成员变量类型
-
// 编译报错
-
private var javastack = "Java技术栈";
2、方法返回类型
-
/**
-
* 编译报错
-
* @return
-
*/
-
public static var getJavastack(){
-
return "Java技术栈";
-
}
3、Lambda 表达式
-
private static void testLambda() {
-
Runnable runnable = () -> System.out.println("javastack");
-
// 编译报错
-
// var runnable = () -> System.out.println("javastack");
-
}
以上 3 种场景是肯定不能使用 var
的,其他场合有待验证。
局部变量类型推断优缺点
优点:简化代码
-
CopyOnWriteArrayList list1 = new CopyOnWriteArrayList();
-
ConcurrentModificationException cme1 = new ConcurrentModificationException();
-
DefaultServiceUnavailableRetryStrategy strategy1 = new
-
DefaultServiceUnavailableRetryStrategy();
-
var list2 = new CopyOnWriteArrayList<>();
-
var cme2 = new ConcurrentModificationException();
-
var strategy2 = new DefaultServiceUnavailableRetryStrategy();
从以上代码可以看出,很长的定义类型会显得代码很冗长,使用 var 大大简化了代码编写,同时类型统一显得代码很对齐。
缺点:掩盖类型
-
var token = new JsonParserDelegate(parser).currentToken();
看以上代码,不进去看返回结果类型,谁知道返回的类型是什么?所以这种情况最好别使用 var
,而使用具体的抽象类、接口或者实例类型。
var关键字原理
var其实就是 Java 10 增加的一种语法糖而已,在编译期间会自动推断实际类型,其编译后的字节码和实际类型一致,如以下例子所示。
-
private static void testByteCode() {
-
String javastack1 = "javastack";
-
var javastack2 = "javastack";
-
}
编译成字节码后:
-
private static testByteCode()V
-
L0
-
LINENUMBER 22 L0
-
LDC "javastack"
-
ASTORE 0
-
L1
-
LINENUMBER 23 L1
-
LDC "javastack"
-
ASTORE 1
-
L2
-
LINENUMBER 24 L2
-
RETURN
-
L3
-
LOCALVARIABLE javastack1 Ljava/lang/String; L1 L3 0
-
LOCALVARIABLE javastack2 Ljava/lang/String; L2 L3 1
-
MAXSTACK = 1
-
MAXLOCALS = 2
可以看出 javastack1
和 javastack2
都是虚拟机所认识的的本地变量类型: java.lang.String
,虚拟机并不认识 var, 所以 var
并不神奇
2.GC改进和其他内务管理
JDK 10中有2个JEP专门用于改进当前的垃圾收集元素。
第一个垃圾收集器接口是(JEP 304),它将引入一个纯净的垃圾收集器接口,以帮助改进不同垃圾收集器的源代码隔离。
预定用于Java 10的第二个JEP是针对G1的并行完全GC(JEP 307),其重点在于通过完全GC并行来改善G1最坏情况的等待时间。G1是Java 9中的默认GC,并且此JEP的目标是使G1平行。
3.线程本地握手(JEP 312)
JDK 10将引入一种在线程上执行回调的新方法,因此这将会很方便能停止单个线程而不是停止全部线程或者一个都不停。
4.备用内存设备上的堆分配(JEP 316)
允许HotSpot VM在备用内存设备上分配Java对象堆内存,该内存设备将由用户指定。
5.其他Unicode语言 - 标记扩展(JEP 314)
目标是增强java.util.Locale及其相关的API,以便实现语言标记语法的其他Unicode扩展(BCP 47)。
6.基于Java的实验性JIT编译器(JEP 317)
Oracle希望将其Java JIT编译器Graal用作Linux / x64平台上的实验性JIT编译器。
7.根证书(JEP 319)
这个的目标是在Oracle的Java SE中开源根证书。
8.根证书认证程序(CA)
这将使OpenJDK对开发人员更具吸引力,它还旨在减少OpenJDK和Oracle JDK构建之间的差异。
9.将JDK生态整合到单个存储库中(JEP 296)
此JEP的主要目标是执行一些内存管理,并将JDK生态的众多存储库组合到一个存储库中。
10.删除Native-Header生成工具(javah)(JEP 313)
从JDK中移除了javah工具,这个很简单并且很重要。