当前位置: 首页 > 科技观察

在十分钟内从Java8到Java15

时间:2023-03-16 00:01:46 科技观察

此博客将向您展示自Java7以来添加的重要新功能的示例。我将展示每个Java版本中的至少一项重大改进,一直到2020年秋季发布的Java15。Java现在完全支持lambdas,函数式编程。、通过var进行类型推断、具有简单构造函数的不可变集合和多行字符串。此外,还有令人兴奋的新实验功能,例如数据类(记录)和密封类。最后,我将讨论JavaREPL,它为快速实验提供了巨大的价值。函数式编程(Java8)在Java8中,添加了函数式编程和lambda作为语言特性。函数式编程的两个核心范式是将函数提升为一等公民的不可变值和方法。数据经过一系列修改步骤,其中每个步骤都需要一些输入并将其映射到新的输出。函数式编程可以在Java中与Streams和null-safemonads(可选)一起使用,如下所示...ListstringList=Arrays.asList("Hello","World","How","Are","You","Today");//functionalstylestringList.stream().filter(s->s.equals("Hello")||s.equals("Are")).map(s->s+"String").forEach(System.out::println);Stream(Java8)对于一般的计算机程序,通常需要处理值列表并对每个值执行给定的转换。在Java8之前,您必须使用for循环来进行这种转换,但从现在开始,您可以按如下方式使用Streams:Stream.of("hello","great").map(s->s+"world").forEach(System.out::println);>helloworld>greatworldmap函数将一个lambda作为输入,该lambda将应用于流中的所有元素。流可以(通过转换)处理列表、集合和映射。感谢Streams,您可以摆脱代码中几乎所有的循环!Optionals(Java8)Java中的另一个常见问题是空指针异常。所以Java引入了Optional——一个monad,它包装了一个可能为null也可能不为null的引用。可以以功能方式将更新应用于此Optional:Optional.of(newRandom().nextInt(10)).filter(i->i%2==0).map(i->"numberiseven:"+i).ifPresent(System.out::println);>numberiseeven:6在上面的代码片段中,我们创建了一个随机数,将其包装在一个Optional对象中,然后只打印偶数。JShell(Java9)最后,我们有一个名为JShell的JavaREPL!相反,您可以一次执行一条命令并立即查看结果。下面是一个简单的例子:$/bin/jshelljshell>System.out.println("helloworld")helloworld熟悉JavaScript或Python等解释型语言的人早就对REPL感到满意,但到目前为止缺少此功能到目前为止在Java中。JShell允许定义变量,但也允许定义更复杂的实体,例如多行函数、类和执行循环。此外,JShell支持自动完成,如果您不知道给定Java类提供的确切方法,它会派上用场。不可变集合的工厂方法(Java9)很长一段时间以来,Java中缺少列表的简单初始化,但现在已经不复存在了。以前,您必须这样做:jshell>Listlist=Arrays.asList(1,2,3,4)list==>[1,2,3,4]现在简化如下:jshell>Listlist=List.of(1,2,3,4)b==>[1,2,3,4]这个(...)方法存在于列表、集合和映射中。他们都用一行简单的代码创建了一个不可变对象。使用var进行类型推断(Java10)Java10引入了新的var关键字,它允许省略变量的类型。jshell>varx=newHashSet()x==>[]jshell>x.add("apple")$1==>true在上面的代码片段中,编译器可以将x的类型推断为HashSet。此功能有助于减少样板代码并提高可读性。不过它有一些限制:您只能在方法体内使用var,并且编译器会在编译时推断类型,因此所有内容仍然是静态类型的。单一源文件启动(Java11)以前,当编写一个由一个文件组成的简单Java程序时,您必须先用javac编译该文件,然后用Java运行它。在Java11中,您可以使用一条命令完成这两个步骤。首先,定义一个单一的源文件,Main.java:/Main.javahelloworld对于只包含一个Java类的简单启动程序或实验,这种启动单个源文件的能力将使您的生活更轻松。Switch表达式(Java12)Java12为我们带来了Switch表达式。快速演示此表达式与旧的switch语句有何不同。旧的switch语句定义了程序的流程:jshell>vari=3jshell>Strings;jshell>switch(i){...>case1:s="one";break;...>case2:s="two";break;...>case3:s="three";break;...>default:s="unknownnumber";...>}jshell>ss==>"three"相反,新的switch表达式返回One值:jshell>vari=3;jshell>varx=switch(i){...>case1->"one";...>case2->"two";...>case3->"three";...>default->"unknownnumber";...>};x==>"three"综上所述,旧的switch语句用于程序流,新的switch表达式解析为一个值。请注意,这个新的switch语句是一个映射函数:只有一个输入(上面例子中的i)和一个输出(这里是x)。事实上,这是一种模式匹配特性,有助于使Java更符合函数式编程原则。类似的switch语句在Scala中已经存在了一段时间。需要注意的几件事:我们使用箭头而不是双点->不需要Break当考虑所有可能的情况时可以省略默认值要在Java12中启用此功能,请使用--enable-preview--source12multilineStrings(Java13)你有没有定义过长的多行字符串,比如JSON或XML?到目前为止,您可能已将所有内容压缩到一行并使用换行符n,但这会使字符串更难阅读。Java13自带多行字符串!示例:publicclassMain{publicstaticvoidmain(String[]args){vars="""{"recipe":"watermelonsmoothie","duration":"10mins","items":["watermelon","lemon","parsley"]}""";System.out.println(s);}}现在,我们通过单个文件启动并运行主要方法:java--enable-preview--source13Main.java{"recipe":"watermelonsmoothie""duration":"10mins","items":["watermelon","lemon","parsley"]}生成的字符串跨越多行,引号""原封不动,即使有制表符也保留了!数据类:RecordRecord(Java14)在本文的所有新特性中,这可能是我最兴奋的一个:Java终于有了数据类!这些类使用record关键字声明,并具有自动获取器、构造函数和equals()方法等。简而言之,您可以摆脱大量样板代码!jshell>recordEmployee(Stringname,intage,Stringdepartment){}|createdrecordEmployeejshell>varx=newEmployee("Anne",25,"Legal");x==>Employee[姓名=Anne,age=25,department=Legal]jshell>x.name()$2==>"Anne"Scala对案例类有类似的功能,Kotlin对数据类也有类似的功能。到目前为止,在Java中,许多开发人员使用Lombok,它提供了许多现在激发Java14记录的功能。有关详细信息,请参阅Baeldung的这篇文章。instanceofwithoutCast(Java14)早期版本的Java已经包含instanceof关键字:Objectobj=newString("hello");if(objinstanceofString){System.out.println("Stringlength:"+((String)obj).length());}Viewraw不幸的是:首先我们检查s是否是String类型,然后再次转换它以获得它的长度。现在使用Java14,编译器足够聪明,可以在instanceof检查后自动推断类型:Objectobj=newString("hello");if(objinstanceofStringmystr){System.out.println("Stringlength:"+mystr.length());}密封类(Java15)使用sealed关键字,您可以限制哪些类可以扩展给定的类或接口。下面是一个例子:publicsealedinterfaceFruitpermitsApple,Pear{StringgetName();}publicfinalclassAppleimplementsFruit{publicStringgetName(){return"Apple";}}publicfinalclassPearimplementsFruit{publicStringgetName(){return"Pear";}}那么这对我们有什么帮助呢?好吧,现在你知道有多少水果了。事实上,这是在完全支持模式匹配的方向上迈出的重要一步,您可以在模式匹配中像对待枚举一样对待类。此密封功能与之前介绍的新开关表达式配合得很好。奖励:自Java8起更新的许可条款本文的最后一个主题:许可。大多数人都听说过Oracle停止了Java8(免费商业版)更新。所以这里是您的选择:使用更新的OracleJDK版本(Oracle在每次发布后提供6个月的免费安全更新)使用旧版本的JDK,风险自负使用旧的OpenJDKJava版本,这些版本仍然是安全更新从开源社区或第三方供应商处获得。向Oracle支付主要支持费用(例如Java8:支持到2030年)下面您可以看到每个JDK的暂定Oracle支持期:>每个JDK的Oracle支持时间表Oracle的新许可模型受新发布周期的影响:Oracle将发布一个新每6个月更新一次Java版本。这个新的发布周期帮助Oracle更快地改进Java,通过实验性功能获得更快的反馈,并赶上Scala、Kotlin和Python等更现代的语言。总结Java在过去6年里取得了长足的进步,从那时起实际上已经发布了8个新的Java版本!与其他基于JVM的竞争对手(Scala和Kotlin)相比,所有这些令人敬畏的新特性都有助于使Java成为一个有竞争力的选择。