上个月,JavaDevelopmentKit(JDK)11刚刚到来,JDK12也在紧锣密鼓的准备中。万千更新版本的错觉,面对厚厚的Java8/9/10/11入门书籍和教程,问你怕不怕?不仅如此,Java早已在移动应用、服务器应用、Web开发、J2EE企业应用、嵌入式等领域深入人心,甲骨文最近发布了一份Java用户协议,轰动了整个行业,因为Java会收费!一、JDK11那些不容错过的新特性JDK11作为Oracle在历经六个月的更新周期后公开发布的第一个长期支持版本,依然拥有许多实用的特性。局部变量推断Java10引入了一个新的关键字var,可以在定义局部变量时代替类型信息(局部是指方法体内部的变量定义)。在Java10之前,局部变量必须这样定义:Stringtext="HelloJava9";现在您可以使用var而不是String。编译器将从变量赋值中推断出正确的类型。因此,文本的类型是String:vartext="HelloJava10";使用var定义的变量仍然是静态类型的。不能使用不兼容的类型重新分配此类变量。例如下面的代码无法编译:vartext="HelloJava11";text=23;//不兼容的类型也可以通过同时使用var和final来禁止变量的重新赋值:finalvartext="Banana";text="Joe";//Cannotassignavaluetofinalvariable'text'另外,当编译器无法推断出正确的类型时,var是不允许的://Cannotinfertype:vara;varnothing=null;varlambda=()->System.out.println("可惜!");varmethod=this::someMethod;局部变量类型推断在泛型中非常有用。在下面的例子中,current有一个非常复杂的类型Map>,这个类型可以简化成一个var关键字,这样可以节省很多打字时间:varmyList=newArrayList>>();for(varcurrent:myList){//currentisinferedtotype:Map>System.out.println(current);}由于Java11的var关键字也可以用在lambda参数上,所以可以给参数加上注解:Predicatepredicate=(@Nullablevara)->true;tips:在IntellijIDEA中,可以按住CMD/CTRL键,将鼠标悬停在变量上,可以看到推断出的类型(快捷键是Ctrl+J)。HTTP客户端Java9引入了新的HttpClientAPI来处理HTTP请求。在Java11中,这个API已经稳定下来,可以通过java.net包使用。让我们看看这个API能做什么。新的HttpClient支持同步和异步方法。同步请求阻塞当前线程,直到返回响应。BodyHandlers定义预期响应主体的类型(例如字符串、字节数组或文件):varrequest=HttpRequest.newBuilder().uri(URI.create("https://winterbe.com")).GET().build();varclient=HttpClient.newHttpClient();HttpResponseresponse=client.send(request,HttpResponse.BodyHandlers.ofString());System.out.println(response.body());同样的请求也可以异步进行。调用sendAsync不会阻塞当前线程,它会返回一个CompletableFuture来构建一个异步操作管道。varrequest=HttpRequest.newBuilder().uri(URI.create("https://winterbe.com")).build();varclient=HttpClient.newHttpClient();client.sendAsync(请求,HttpResponse.BodyHandlers.ofString()).thenApply(HttpResponse::body).thenAccept(System.out::println);提示:可以省略.GET()调用,因为它是默认调用。以下示例使用POST将数据发送到给定的URL。与BodyHandlers类似,这里使用BodyPublisher来定义请求体中要发送的数据类型,例如字符串、字节数组、文件或输入流:varrequest=HttpRequest.newBuilder().uri(URI.create("https://postman-echo.com/post")).header("Content-Type","text/plain").POST(HttpRequest.BodyPublishers.ofString("Hithere!")).build();varclient=HttpClient.newHttpClient();varresponse=client.send(request,HttpResponse.BodyHandlers.ofString());System.out.println(response.statusCode());//200下面的例子演示了通过BASIC-AUTH进行认证的方法:varrequest=HttpRequest.newBuilder().uri(URI.create("https://postman-echo.com/basic-auth")).build();varclient=HttpClient.newBuilder().authenticator(newAuthenticator(){@OverrideprotectedPasswordAuthenticationgetPasswordAuthentication(){returnnewPasswordAuthentication("postman","password".toCharArray());}}).build();varresponse=client.send(request,HttpResponse.BodyHandlers.ofString());System.out。println(response.statusCode());//List、Set、Map等200个集合一个新方法List.of已添加到集合类,例如,它将根据给定的参数创建一个新的不可变列表。List.copyOf创建列表的不可变副本。varlist=List.of("A","B","C");varcopy=List.copyOf(list);System.out.println(list==copy);//true因为list已经是不可变的,所以不需要实际创建列表实例的副本,因此列表和副本将指向同一个副本。但是如果你赋值一个可变列表,copy会生成一个新的实例来保证修改原始列表时不会有副作用:varlist=newArrayList();varcopy=List.copyOf(list);System.out.println(list==copy);//false创建不可变map时,不需要自己创建map的内容,传key和value即可:varmap=Map.of("A",1,"B",2);System.out.println(map);//{B=2,A=1}Java11中的不可变集合仍然使用与原始集合API相同的接口。但是,如果您尝试通过添加或删除元素来改变不可变集合,则会发生java.lang.UnsupportedOperationException。幸运的是,当您尝试改变不可变集合时,IntellijIDEA会警告您。StreamsJava8引入了流的概念,现在它有了三个新方法。Stream.ofNullable可以从单个元素构建流:Stream.ofNullable(null).count()//0dropWhile和takeWhile这两个方法都可以接受谓词对象,这样就可以丢弃流中的一些元素:Stream.of(1,2,3,2,1).dropWhile(n->n<3).collect(Collectors.toList());//[3,2,1]Stream.of(1,2,3,2,1).takeWhile(n->n<3).collect(Collectors.toList());//[1,2]OptionalOptional也增加了几个新的方法,比如现在可以很容易的把optional转成stream,或者给一个空的可选提供另一个可选作为错误的替代:Optional.of("foo").orElseThrow();//fooOptional.of("foo").stream().count();//1Optional.ofNullable(null).or(()->Optional.of("fallback")).get();//String,最基础的fallback字符串类之一,还增加了几个辅助方法,去除空格,Checksforblanks和流字符串:"".isBlank();//true"FooBar".strip();//"FooBar""FooBar".stripTrailing();//"FooBar""FooBar".stripLeading();//"FooBar""Java".repeat(3);//"JavaJavaJava""ABC".lines().count();//3个其他的JVM特性在我看来,以上是Java11相比8最有趣的语言API特性,但是还有很多新特性,比如下列:用于响应式编程的流式APIJava模块系统应用程序类数据共享动态类文件常量JavaREPL(JShell)FlightRecorderUnicode10G1:完全并行垃圾收集器ZGC:可扩展低延迟垃圾收集器Epsilon:NashornJavaScript引擎,不被推荐No-Opgarbagecollector...2.学不会Java,还要交钱?对于Java的新版本,很多开发者望尘莫及,纷纷表示不要再更新了。我的项目还停留在Java8?话虽如此,事实上,甲骨文在今年4月就宣布,从2019年1月起,JavaSE8公共更新将不会在没有商业许可的情况下提供给商业、商业或生产用途。也就是说,如果以后开发者想使用JDK8,Oracle不会提供免费的技术支持,需要额外收费。所以一般来说,还是建议开发者换用最新版本的Java11。但是此时,根据国外网友@StephenColebourne发表的一篇名为《Oracle's Java 11 trap - Use OpenJDK instead!》的博文,我们注意到在Java11中,Oracle悄悄地更新了用户协议(https://www.oracle.com/technetwork/java/javase/terms/license/javase-license.html):简而言之:新版本的OracleJDK不能用于数据处理,业务,产品,或内部商业用途(需要购买许可证),仅免费用于开发、测试、原型制作、演示。正是这次修改,意味着免费了23年的Java即将走上收费之路。如果开发者还是像往常一样下载OracleJDK,放到商业项目中,以后可能会出现很多商业纠纷。3.OracleJDK收费,企业和开发者怎么办?说到Java的商业纠纷,我们不禁想起轰动一时、长达8年的甲骨文和谷歌对Java的侵权案:1995年,Sun发布了Java;需要介绍的是,2006年,Sun公司开源了其Java项目——OpenJDK,但并未开源之前的Java项目SunJDK(现为OracleJDK);2009年,甲骨文以74亿美元收购Sun,获得Java版权,其中还包括Sun开发的Java商业项目的版权;2010年8月,甲骨文认为谷歌Android系统抄袭了37个JavaAPI代码段,而这些代码是甲骨文商业私有JDK(OracleJDK)的一部分,因此将谷歌告上法庭,要求赔偿26亿美元;经过8年的调解和上诉,此案终于在今年3月落下帷幕,美国联邦巡回法院裁定谷歌向甲骨文赔偿88亿美元。案子之所以没有说完,是因为谷歌不服判决,仍在向最高法院上诉。而谷歌在处理这起官司的时候,可能正在认真思考自己乃至整个公司Android系统的下一步发展:如何摆脱甲骨文?于是,在2015年底,我们见证了Google宣布将Java应用程序的接口(API)从OracleJavaAPI替换为开源OpenJDK。甚至在两年后的谷歌I/O大会上,更是令人震惊地宣布Kotlin成为Android开发的第一级编程语言,使其与Java并驾齐驱,另一方面也与其展开竞争。看看甲骨文这次对JDK11用户协议的修改,从甲骨文的角度不难理解他的行为。毕竟甲骨文这种纯软件先驱也是商业公司,他需要提供软件的商业版。提高增值服务。但是对于使用OracleJDK的开发者或者公司来说,情况就变得不一样了。为了避免和上面提到的谷歌一样的体验,除了付费,我们还有其他选择吗?许多开发者对此展开了激烈的讨论:Java程序员是时候转C#了;改成.NET也没问题;这只是针对JDK11的,不升级也不用Java11也没关系。在采访了几位知名的Java开发者后,他们给出的答案几乎都是,“用Kotlin”。就连微博研发副总经理@TimYang也表示,这种行为直接导致Kotlin成为绝对的赢家。IDEA环境将Java代码粘贴到Kotlin文件中,自动转换。然而,与23岁的Java相比,对于只有7岁的Kotlin,许多开发者仍然感到迷茫。因此,面对JDK8即将停止免费更新支持和JDK11尚未商用的事实,请记住Oracle仍然有一个名为OpenJDK的开源项目。注意:Java9和10不是长期支持(LTS)版本,所以上面的文章没有提到。要说之前OracleJDK和OpenJDK的差距是显而易见的,那么在JDK11中,Oracle非常人性化的尽可能缩小了两者之间的差距,甚至忽略了细微的差距。或者除了OpenJDK,我们之前也发过文章推荐一些实用的JDK,比如AdoptOpenJDKbuilds、RedHatOpenJDKbuilds、AzulZulu等。***,对于Oracle对JDK11的使用协议的修改,你怎么看?欢迎在下方留言分享你的想法。
