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

250 阅读3分钟

在本教程中,请结合实例学习Java 10的特性Local variables Type。推理JDK增强建议(JEP-286)是Java 10中的一项新功能。

什么是java10中的局部变量类型推断?

type inference 是指编译器根据初始化值自动检测数据类型。

它在Java 10中引入了局部变量。

这个功能在其他语言中已经存在,比如Scala、javascript和c#。

让我们看看这个功能在以前的Java版本中是如何工作的。

通常情况下,局部变量的声明方式如下。

在下面的例子中,创建了一个ArrayList ,在Java 5和6版本中持有字符串。

List lists=new ArrayList();  

这里有两个部分,Left-hand sideright-hand side 的相等运算符

left-hand side 是一个变量声明,有一个变量持有的数据类型。

Right-hand side 是初始化,变量被初始化时,可能持有的数据类型。

在这篇文章中,我们将讨论如何用更短、更简单的语法定义局部变量声明。

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

List lists=new ArrayList();

在Java 7中,使用Diamond运算符,以这样的方式减少了代码,即右边的初始化没有数据类型,数据类型从左边的推断而来。

List lists=new ArrayList<>();

在Java 10中,这种简化和减少的代码,以及类型安全,仍然有效。

var lists=new ArrayList();  

编译器假设左边的类型是inferred ,作为右边的一个类型,如果右边没有类型,它将把类型视为一个对象。

编译器如何解释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  

在java10中使用var的类型安全例子

在下面的例子中,创建了本地的String变量,并给同一个本地变量分配了一个整数。

这给出了一个编译错误

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

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

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

在for循环中声明index 变量,如下所示。

 public class Test {
    public static void main(String[] args) {
        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);
        }
    }
}  

java10中方法中的var变量和返回值

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

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;  
 }  
}  

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

局部变量存储了ternary operator 评估的结果。在下面的例子中,结果被推断为String。

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

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

var 不仅指定了数据类型,而且还推断了流。

下面是var stream的例子。

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

本地变量类型推断编译错误

本地变量在使用上也有很多的限制和约束。

下面的情况都会出现编译错误。

  • 没有初始化器的局部变量

这里的局部变量声明了,但没有初始化,它给出的编译错误是:Cannot use 'var' on a variable without initializer

  • 没有用空值初始化的变量

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

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

不允许声明多个局部变量

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

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

  • 不允许本地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() {  
 }  

  • 在catch块中没有var声明

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

public class Test {
    public static void main(String[] args) {
        try {
            // code  
        } catch (var e) {
        }
    }
    
}  
  • Lambda表达式需要一个明确的目标类型

下面的lambda表达式的var初始化引发了一个错误。

像钻石运算符,在右侧,需要目标数据类型才能工作

var helloString = () -> "teststring"; 

-构造函数参数不允许

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

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

Java 10局部变量的干扰 优点 缺点

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

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

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

总结

学习了局部变量的推理类型和在不同Java版本中的例子