Java 10:局部变量类型推理教程及实例

158 阅读4分钟

在本教程中,我们将学习Java 10的特性--局部变量类型推断。JDK Enhancement Proposal(JEP) 286是Java 10的一个新特性。

局部变量类型推理介绍

类型推断是编译器根据初始化值自动检测数据类型。随着Java 10的推出,它被引入到局部变量中。这个功能在其他语言中已经存在,比如Scala、javascript和c#。让我们看看这个功能在以前的Java版本中是如何工作的。通常情况下,局部变量的声明方式如下,在下面的例子中,在Java 5和6版本中创建了一个持有字符串的ArrayList。

List lists=new ArrayList();  

这里有两个部分,等价运算符的左侧和右侧

左手边是变量声明,变量持有的数据类型 右手边是初始化,变量被初始化为可能持有的数据类型。

这篇文章,我们将讨论如何缩短局部变量的声明。

在Java 7中,引入了Diamond操作符,允许在没有类型的情况下使用空括号,变量的声明方式如下 在Java 7之前,字符串的ArrayList可以声明如下

List lists=new ArrayList();

编译器如何解释var类型?

每当遇到局部类型的变量时,它首先检查右侧的等价符号,即初始化器,找出初始化器的类型并将此类型分配给一个变量。

var的使用实例

在下面这一节中,我们将公布var的用法和例子。

基本类型推理例子

在下面的例子中,本地字符串被声明并以字符串常数字面值初始化。另一个局部变量被声明并用于存储字符串的小写结果。类型没有被声明。编译器从其值中自动推断出类型。

public class LocalVariableTypeInferenceHelloWorld {  
 public static void main(String[] args) {  
  var str = "THIS IS STRING"; // equals to String str= "THIS IS STRING";  
  var lowerCaseString = str.toLowerCase(); // equals to String lowerCaseString = str.toLowerCase();  
  System.out.println(lowerCaseString);  
  System.out.println(lowerCaseString.getClass().getTypeName());  
 }  
}  

输出是

this is string  
java.lang.String  

类型安全与var的例子

在下面的例子中,创建了本地字符串变量,并将同一本地变量分配给一个整数。这就产生了编译错误

var str = "test string"; // equals to String str= "test string";  
str=10;  

编译器仍在使用类型安全索引工作。

循环局部变量类型推理的例子

在for循环中声明了索引变量,如下所示。

 for (var i = 1; i <= 10; i++) {  
            var temp= i* 2; // equals to Integer temp=i* 2;  
            System.out.println(temp);  
        } 

对于每个局部变量类型推断的例子

本地变量可以用var保留词来推断,如下所示 在每个迭代过程中为迭代声明变量。

import java.util.ArrayList;  
public class ForEachVarDemo {  
 public static void main(String[] args) {  
  var list = new ArrayList();  
  list.add("abc");  
  list.add("def");  
  list.add("ggg");  
  for (var str : list) {  
   var upperString = str.toUpperCase(); // equal to String upperString = str.toUpperCase();  
   System.out.println(upperString);  
  }  
 }  
}  

方法中的返回值

在一个方法中,声明一个局部变量并返回给调用者。同时,返回值也被存储在另一个局部变量中。

public class MethodLocalVarDemo {  
 public static void main(String[] args) {  
  var number1 = 30;  
  var number2 = 50;  
  var output = sum(number1, number2);  
  System.out.println(output);  
 }  
 private static Integer sum(Integer number1, Integer number2) {  
  var result = number1 + number2;  
  return result;  
 }  
}  

用于存储三元运算结果的局部变量

本地变量用于存储三元运算器的评估结果,在下面的例子中,结果被推断为字符串。

 var result = true? "true": "false";  
System.out.println(result); 

声明一个用于流的局部变量

var不仅用于分配数据类型,也用于推断流。下面是var流的例子。

var list = new ArrayList();  
  list.add("abc");  
  list.add("def");  
  list.add("ggg");  
  var stream = list.stream();  
  stream.forEach((string) -> {  
   System.out.println(string);  
  });  

编译错误

本地变量的使用也有很多限制和约束。下面的情况都会出现编译错误。

没有初始化器的局部变量

这里的局部变量被声明但没有初始化,它给出的编译错误是 "不能在没有初始化器的变量上使用'var'"。

没有用空值初始化的变量

如果var变量初始化为空值,编译器会产生错误--无法推断初始化为'null'的局部变量的类型

没有多变量或复合变量声明

不允许声明多个局部变量

var m=5,n=2,p=3;  // not allowed  
int m=5,n=2,p=3;  //  allowed  

如果我们声明了多个局部变量,它给出了var'在复合声明中是不允许的'。

不允许本地变量数组初始化

像下面这样声明的数组不允许用于局部变量。

上面这行代码给出的错误是数组初始化器需要一个明确的目标类型

不是类的实例变量

不允许用局部变量声明的实例变量或类变量。

public class ClassLocalDemo {  
 var memberVariable=10;  
 public static void main(String[] args) {  
 }  
}  

没有方法参数/参数

方法签名中没有声明局部变量。

public class ClassLocalDemo {  
 public static void main(String[] args) {  
 }  
 public static void method(var parame) {  
 }  
}  

方法返回类型中没有var

方法的返回类型不应该是var字样,并且会引发编译错误。

public static var method() {  
 }  

var不允许出现在catch块中,如下图所示

try {  
   // code  
   } catch (var e) {  
       }  

Lambda表达式需要一个明确的目标类型

下面的lambda表达式的var初始化引发了一个错误。像钻石运算符,右侧,需要目标数据类型才能工作。

var helloString = () -> "teststring"; 

不允许构造器参数

var不应该与构造函数参数一起使用,如下图所示

public class Demo {  
 public Demo(var a) {  
    
 }  
}  

优点

  • 冗长的代码
  • 可读性和更少的类型化

缺点
Java 7中的局部变量声明和钻石运算符相冲突,使开发人员感到困惑。

var保留字
var不是一个关键词,是保留字。我们不能用'var'这个词来给变量和方法命名,这些是无效的。