java var类型_探索新的Java 10“ var”类型:简介和动手教程

java var类型

重要要点

  • Java 10引入了一个闪亮的新功能:局部变量的类型推断。 对于局部变量,您现在可以使用特殊的保留类型名称“ var”,而不是实际类型。
  • 提供此功能是为了增强Java语言并将类型推断扩展到使用初始化程序声明的局部变量。 这减少了所需的样板代码,同时仍保持Java的编译时类型检查。
  • 由于编译器需要通过查看右侧(RHS)来推断var实际类型,因此此功能在某些情况下具有局限性,例如在初始化数组和流时。
  • 在本动手教程中进行实验,以了解如何使用新的“ var”类型减少样板代码。

在本文中,我将通过示例介绍新的Java SE 10功能“ var”类型。 您将学习如何在代码中正确使用它,以及何时不能使用它。

介绍

Java 10引入了一个闪亮的新功能:局部变量的类型推断。 对于局部变量,您现在可以使用特殊的保留类型名称“ var”,而不是实际类型,如下所示:

var name = “Mohamed Taman”;

提供此功能是为了增强Java语言并将类型推断扩展到使用初始化程序声明的局部变量。 这减少了所需的样板代码,同时仍保持Java的编译时类型检查。

由于编译器需要通过观察将R ight- HS IDE(RHS)推断出VAR实际类型,此功能在某些情况下限制。 过一会儿我要提一下,继续阅读。 现在让我们来看一些简单的例子。

嘿,等等,等等 在跳入代码之前,您将需要使用IDE像往常一样尝试新功能。 好消息是市场上有很多,所以您可以在许多IDE(例如Apache NetBeans 9,IntelliJ IDEA 2018或新的Eclipse)中选择自己喜欢的,支持Java SE 10的IDE。

就我个人而言,我始终喜欢使用交互式编程环境工具来快速学习Java语言语法,探索新的Java API及其功能,甚至用于复杂代码的原型设计。 这不是繁琐的编辑,编译和执行代码的过程,该过程通常涉及以下过程:

  1. 编写一个完整的程序。
  2. 编译并修复所有错误。
  3. 运行程序。
  4. 找出问题所在。
  5. 编辑它。
  6. 重复该过程。

再次好消息是,您将使用自Java SE 9以来Java SE JDK内置和随附的JShell工具,该工具是该版本的旗舰功能。

什么是JShell

现在,Java使用JShell工具实现了丰富的REPLR e- E valuate - Pint- L oop)实现,称为J ava S hell,它是一种交互式编程环境 那么,什么是魔术呢? 这很简单。 JShell提供了一个快速友好的环境,使您可以快速探索,发现和试验Java语言功能及其广泛的库。

使用JShell,您可以一次输入一个程序元素,立即查看结果,并根据需要进行调整。 因此,JShell用其read-evaluate-print循环代替了繁琐的编辑,编译和执行循环。 在JShell中,您不是编写完整的程序,而是编写JShell命令和Java代码段。

输入代码段时,JShell会立即读取,评估并打印其结果。 然后循环执行以针对下一个片段再次执行此过程。 因此,JShell及其即时反馈可以吸引您的注意力,提高您的性能,并加快学习和软件开发过程。

这对于JShell来说已经足够了,InfoQ最近已经发布了对该工具的详尽介绍。 为了深入学习并了解有关JShell的所有功能的更多信息,我已经录制了有关此主题的完整视频培训,标题为“ 使用JShell进行Java 10编程实践[视频] ”,它可以帮助您精通该主题,并且可以通过以下途径获得Packt或Udemy 。

现在,让我们来看一些简单的示例,以了解使用JShell可以使用此新的var类型功能来完成的工作

必备软件

为了可能与JShell一起使用,我假设您已经安装了Java SE或JDK 10+,并且JDK bin文件夹中的工具被配置为可以从系统中的任何位置访问,如果没有,这里是安装JDK 10+ 最新版本的链接。 。

启动JShell会话

要在以下位置启动JShell会话:

  1. Microsoft Windows打开命令提示符,然后键入jshell并按Enter。
  2. 在Linux上,打开一个shell窗口,然后键入jshell并按Enter。
  3. 在macOS(以前称为OS X)上时,打开一个Terminal窗口,然后键入以下命令“ jshell ”并按Enter。

塔拉阿! 此命令执行一个新的JShell会话,并在jshell>提示符下显示此消息:

|  Welcome to JShell -- Version 10.0.1
|  For an introduction type: /help intro
jshell>

使用“ var”类型。

现在,您已经安装了JDK 10,让我们开始使用JShell,让我们直接跳到终端以通过示例开始破解var类型功能。 只需在jshell提示符下输入接下来要介绍的每个片段,我将把结果留给您练习。 如果您先偷偷摸摸地看一下代码,您会发现它看起来错了,因为没有分号。 尝试一下,看看它是否有效。

简单类型推断案例

这是var类型的基本用法,在下面的示例中,编译器可以将RHS推断为String文字:

var name = "Mohamed Taman"
var lastName = str.substring(8)
System.out.println("Value: "+lastName +" ,and type is: "+ lastName.getClass().getTypeName())

不需要分号,因为JShell是一个交互式环境。 仅当同一行上有多个语句,或者声明的类型或方法中包含多个语句时才需要分号,并且您将在以下示例中看到分号。

var类型和继承

同样,多态仍然有效。 在继承的世界中,可以将var type的子类型分配给var type的超类型,这是通常情况,如下所示:

import javax.swing.*
var password = new JPasswordField("Password text")
String.valueOf(password.getPassword()) // To convert password char array to string to see the value
var textField = new JTextField("Hello text")
textField = password
textField.getText()

但是不能将超类型var分配给子类型var,如下所示:

password = textField

这是因为JPasswordField是JTextField类的子类。

var和编译时安全

那么现在,错误的分配又如何呢? 不兼容的变量类型不能互相分配。 一旦编译器推断出var的实际类型,就不能为以下内容分配错误的值:

var number = 10
       number = "InfoQ"

那么,这里发生了什么? 此处的编译器只是将“ var number = 10 ”替换为“ int number = 10 ”以进行进一步检查,因此仍保持安全性。

带有集合和泛型的var

好吧,让我们看看var如何与Collection元素类型推断和泛型一起工作。 让我们从集合开始。 在以下情况下,编译器可以推断集合元素的类型:

var list = List.of(10);

此处无需进行强制转换,因为编译器已推断出正确的元素类型int

int i = list.get(0); //equivalent to: var i = list.get(0);

在以下情况下,情况有所不同,编译器将其视为对象(不是整数)的集合,这是因为当您使用菱形运算符时,Java已经需要LHS (左手侧)上的类型来推断RHS上的类型。 ,让我们看看如何;

var list2 = new ArrayList<>(); list2.add(10); list2
int i = list2.get(0) //Compilation error
int i = (int) list2.get(0) //need to cast to get int back

对于泛型,最好在RHS上使用特定类型(而不是菱形运算符),如下所示:

var list3 = new ArrayList(); list3.add(10); System.out.println(list3)
int i = list3.get(0)

让我们跳下去看看var类型如何在不同类型的循环中工作:

var类型用于循环

我们首先检查基于索引的普通For Loop

for (var x = 1; x <= 5; x++) {
           var m = x * 2; //equivalent to: int m = x * 2;
          System.out.println(m); 
}

这是它与For Each循环一起使用的方式

var list = Arrays.asList(1,2,3,4,5,6,7,8,9,10)
    for (var item : list) {
          var m = item + 2;
          System.out.println(m);
}

所以现在我在这里有一个问题,var是否可以与Java 8 Stream一起使用? 让我们看下面的例子;

var list = List.of(1, 2, 3, 4, 5, 6, 7)
   var stream = list.stream()
   stream.filter(x ->  x % 2 == 0).forEach(System.out::println)

三元运算符的var类型

三元运算符呢?

var x = 1 > 0 ? 10 : -10
int i = x

现在,如果您在三元运算符的RHS上使用不同类型的操作数,该怎么办? 让我们来看看:

var x = 1 > 0 ? 10 : "Less than zero"; System.out.println(x.getClass()) //Integer
var x = 1 < 0 ? 10 : "Less than zero"; System.out.println(x.getClass()) // String

这两个例子是否表明var的类型是在运行时确定的? 让我们以旧的方式做同样的事情:

Serializable x = 1 < 0 ? 10 : "Less than zero"; System.out.println(x.getClass())

Serializable ,它是两个不同操作数的通用兼容且最专业的类型(最不专业的类型为java.lang.Object )。

String和Integer都实现Serializable。 整数从int自动装箱。 换句话说,序列化是两个操作数的LUB(LûPPER ound)。 因此,这表明在我们的第三个示例中,var类型也是Serializable

让我们进入另一个主题:将var类型传递给方法。

带有方法的var类型

我们首先声明一个名为squareOf的方法,该方法的一个参数为BigDecimal类型,该方法将按如下所示返回此参数的平方:

BigDecimal squareOf(BigDecimal number) {
      var result= number.multiply(number);
      return result;
  }

var number = new BigDecimal("2.5")
number = squareOf(number)

现在让我们看看它如何与泛型一起工作。 再次让我们声明一个名为toIntgerList的方法,该方法的一个参数类型为T类型的List (泛型类型),它使用Streams API如下返回该参数的基于整数的列表:

 List toIntgerList(List numbers) {
               var integers = numbers.stream()
                                    .map(Number::intValue)
                                    .collect(Collectors.toList());
               return integers;
}

         var numbers = List.of(1.1, 2.2, 3.3, 4.4, 5.5)
         var integers = toIntgerList(numbers)

带有匿名类的var

最后,让我们看看将var与匿名类一起使用。 让我们通过实现Runnable接口来利用线程,如下所示:

var message = "running..." //effectively final
         var runner = new Runnable(){
                  @Override
                  public void run() {
                           System.out.println(message);
                  }}

            runner.run()

到目前为止,我已经介绍了闪亮的新Java 10功能“ var”类型,它减少了样板代码,同时保持了Java的编译时类型检查。 您通过示例展示了可以完成的工作。 现在,您将了解var类型的局限性以及不允许使用的类型。

“无限制”限制

现在,您将看一些简单的示例,以了解使用var类型功能无法完成的工作。 因此,让我们跳到终端,通过一些示例来破解限制。

jshell提示的结果将说明代码有什么问题,因此您可以利用交互式即时反馈。

您应该使用一个值进行初始化

首先,也是最简单的事情是,此处不允许使用没有初始化程序的变量。

var name;

您将得到一个编译错误; 因为编译器无法推断此局部变量x的类型。

不允许复合声明

尝试运行此行;

var x = 1, y = 3, z = 4

您将收到此错误消息,复合声明中不允许使用“ var”。

没有明确的分配

尝试如下创建一个称为testVar的方法,只需将其复制并粘贴到JShell中:

void testVar(boolean b) {
       var x;
       if (b) {
           x = 1;
       } else {
           x = 2;
       }
      System.out.println(x);
   }

它不会创建方法,而是会引发编译错误。 如果没有初始化程序,则不能在变量上使用“ var”。 即使是类似以下的赋值(称为“ 确定性赋值” ),也不适用于var。

空分配

不允许空分配,如下所示;

var name = null;

这将引发异常“变量初始值设定项为'null'”。 因为null不是类型。

使用Lambdas

另一个示例,没有Lambda初始化程序。 就像钻石算子的情况一样,RHS已经需要来自LHS的类型推断。

var runnable = () -> {}

将抛出此异常,“ lambda表达式需要显式的目标类型”。

var和方法参考

没有方法引用初始化程序,类似于lambda和diamond运算符:

var abs = BigDecimal::abs

将抛出此异常:“方法引用需要显式的目标类型”

var和数组初始化

并非所有的数组初始值设定项都起作用,让我们看看带有[]的var如何不起作用:

var numbers[] = new int[]{2, 4, 6}

错误将是:不允许将'var'作为数组的元素类型。

以下内容也不起作用:

var numbers = {2, 4, 6}

错误是:“数组初始化器需要显式的目标类型”

就像上一个示例一样,var和[]在LHS上不能一起使用:

var numbers[] = {2, 4, 6}

错误:不允许将“ var”作为数组的元素类型

仅以下数组初始化有效:

var numbers = new int[]{2, 4, 6}
var number = numbers[1]
number = number + 3

不允许使用var字段

class Clazz {
  private var name;
}

不允许使用var方法参数

void doAwesomeStuffHere(var salary){}

没有var作为方法返回类型

var getAwesomeStuff(){ return salary; }

catch子句中没有var

try {
         Files.readAllBytes(Paths.get("c:\temp\temp.txt"));
      } catch (var e) {}

编译时var类型在后台发生了什么?

“ var”实际上只是一个语法糖,它不会在编译后的代码中引入任何新的字节码构造,并且在运行时JVM没有针对它们的特殊指令。

结论。

在本文的最后,您介绍了“ var”类型是什么,以及此功能如何减少样板代码,同时保持Java的编译时类型检查。

然后,您了解了新的JShell工具(Java的REPL实现),它可以帮助您快速学习Java语言,并探索新的Java API及其功能。 您还可以使用JShell代替复杂的代码原型,而不用传统的单调乏味的代码编辑,编译和执行周期。

最后,您了解了所有var类型的功能和限制,例如可以使用和不能使用的地方。 为您写这篇文章很有趣,所以我希望您喜欢它并发现它有用。 如果是这样,那么请传播这个词。

资源资源

  1. JDK 10文档
  2. 通过JShell动手进行Java 10编程 。
  3. 干净代码Java SE 9入门 。
  4. JDK 10和JRE 10安装概述 。
  5. JEP 286:局部变量类型推断 。
  6. 确定分配

翻译自: https://www.infoq.com/articles/java-10-var-type/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

java var类型

你可能感兴趣的:(java var类型_探索新的Java 10“ var”类型:简介和动手教程)