java版本越新越好吗_这些Java9 超牛的新特性,你竟然还没用过?

原标题:这些Java9 超牛的新特性,你竟然还没用过?

关注

425e9bed414b1c1ebba9bee7f13d7dcd.png

汪伟俊|作者

Java技术迷| 出品

互联网技术的更新日新月异,而对于jdk,大部分人平时都是使用的jdk1.8,然而,如今jdk已经更新到了15马上变16,本篇文章我们就来看看jdk9到底更新了一些什么内容。

目录结构变化

有关jdk9的下载安装与环境配置在这里就不作介绍了,直接来看看它与jdk8的第一个区别,目录结构的变化。

7983eee31c524c92aa8de1d491651a0e.png

上图是jdk8的目录结构,下图是jdk9的目录结构:

d7f84afa6fd9043b7ea138bd3e5e7c80.png

两者最明显的区别在于jdk9中已经不包含jre了,其它内容变化倒是不大。

模块化

我们知道,Java编写的项目是比较臃肿的,编译运行需要耗费大量的时间,为此,java9提供了模块化,使得开发者可以指定项目具体需要使用哪些类库,以排除无关紧要的jar包,增加项目运行效率。

首先创建一个Java项目:

4c699cfda7c5aa470d362ab83bbe28df.png

在该项目下创建两个模块,创建方法为 右击项目-->New-->Module:

05ee8a038fd0d826b2c09d4972b1222e.png

a633dcac3f5c1c94fcc52abb09426680.png

模块创建完成后,在module-1中编写一个Bean:

packagecom.wwj.bean;

publicclassPerson{

privateString name;

privateintage;

publicPerson{

}

publicPerson(String name, intage){

this.name = name;

this.age = age;

}

publicString getName{

returnname;

}

publicvoidsetName(String name){

this.name = name;

}

publicintgetAge{

returnage;

}

publicvoidsetAge( intage){

this.age = age;

}

@Override

publicString toString{

return"Person{"+

"name='"+ name + '''+

", age="+ age +

'}';

}

}

然后我们在module-2中创建一个测试文件:

2330bae5a179bac9946a24eac5de7c5f.png

会发现在module-2中是无法使用module-1中的Person类的,这是因为jdk9对项目进行了模块化,若想要使用到其它模块的类,需要作如下操作。

在module-1中创建module-info文件:

e404bd63ac50407d13867610ad8a8e26.png

编写如下内容:

modulemodule1 {

// 导出包

exportscom.wwj.bean;

}

并在module-2中创建module-info文件,编写如下内容:

modulemodule2 {

// 引入模块

requiresmodule1;

}

这样我们就可以顺利地使用到module-1中com.wwj.bean包下的类了:

bd882089785db5d9062457eedc643965.png

再举个例子,比如你想打印日志,你就需要使用Logger类,然而:

eeef0f34d4adce4aa7f3d1318676ecca.png

此时Logger类也是报错的,而且你会发现导包是导入不了的,此时我们就需要在module-info中引入Logger模块:

modulemodule2 {

requiresmodule1;

requiresjava.logging;

}

这样就能够使用Logger类了:

5506c60f200a8c9b11046cdd8282825d.png

通过这样的方式,使得虚拟机在加载项目时只会去加载module-info中配置的模块,从而大大提升了运行效率。

jshell命令

在jdk9之前,我们若是想执行一个非常简单的程序,比如做一个加法,你需要创建java文件,然后编译执行。

这显然非常繁琐,那它能不能够像Python那样有一个交互式的编程环境呢?为此,jdk9提供了jshell。

使用方法非常简单,在cmd窗口中输入jshell:

603fd1840482d3144746bc781f89a8df.png

在jshell中,我们能够进行输出、定义变量、计算等等很多操作,jshell也会在我们按下回车后立即给予我们反馈:

ce93997f81b68fee2e1c7671f7a9f0a9.png

创建方法并调用:

edb6da334b07c0b0cfaba8d1646aa8e2.png

jshell还提供了一些非常好用的命令,比如: /list , 通过它能够查看历史执行的命令:

jshell>/list

1 : System.out.println("Hello World

3 : System.out.println("Hello World

4 : int i = 10;

5 : int j = 10;

6 : int result = i + j;

7 : System.out.println(result);

8 : public int add(int i,int j){

return i + j;

}

9 : System.out.println(add(i,j));

/imports , 查看导入的包:

jshell>/imports

| import java.io.*

| import java.math.*

| import java.net.*

| import java.nio.file.*

| import java.util.*

| import java.util.concurrent.*

| import java.util.function.*

| import java.util.prefs.*

| import java.util.regex.*

| import java.util.stream.*

/vars , 查看定义的变量:

jshell>/vars

| int i = 10

| int j = 10

| int result = 20

/methods , 查看定义的方法:

jshell>/methods

| int add(int,int)

/edit ,弹出对话框用于修改代码:

39da7a5f7cb1caa9e5004580cf5b9941.png

前言多版本兼容Jar包

当一个新版本的jdk出现时,开发者并不愿意立马将其开发环境切换到新的版本,因为它的很多项目还是用之前的jdk进行开发的,当切换了新版本的jdk后,很可能会因为其不兼容一些老的jar包从而导致项目出错。

jdk9考虑到了这一点,其多版本兼容jar包的功能可以使开发者创建仅在特定版本的java环境中运行库程序选择使用的版本。

现在有这样一个项目,其中有两个包,一个java包,一个java-9包。

java包中有两个类,分别是:

publicclassGenerator{

publicSet createStrings{

Set strings = newHashSet;

strings.add( "Java");

strings.add( "8");

returnstrings;

}

}

publicclassApplication{

publicstaticvoidtestMultiJar{

Generator gen = newGenerator;

System.out.println( "Generated strings: "+ gen.createStrings);

}

}

而java-9中的类为:

publicclassGenerator{

publicSet createStrings{

returnSet.of( "Java", "9");

}

}

现在我们将对这个项目进行打包,得到一个.jar文件——multijar.jar。

下面就来测试一下,新建一个Java8的项目,并编写测试代码:

publicclassMultiJar{

publicstaticvoidmain(String[] args){

Application.testMultiJar;

}

}

记得将刚才的jar包导入到项目中,运行结果为:

Generated strings: [Java, 8]

我们再将这段代码放到Java9环境的项目中运行一下,得到结果:

Generated strings: [9, Java]

可以看到,同一段代码在不同环境下会有对应的不同表示,这就是多版本兼容的jar包。

接口可以定义私有方法了

从jdk9开始,接口可以定义私有方法了,具体的话也没有什么好说的,直接看代码:

publicinterfaceInterfaceTest{

//jdk7中只能声明全局常量(使用public static final修饰)和抽象方法(使用public abstract修饰)

intnum = 10;

voidadd( inti, intj);

//jdk8中还能够声明静态方法和默认方法

staticvoidstaticMethod{

}

defaultvoiddefaultMethod{

}

//jdk9中能够定义私有方法

privatevoidprivateMethod{

}

}

集合中的泛型

在jdk8以前,我们若想定义一个带有泛型的集合,必须这样编写:

Set set = newHashSet;

而在jdk8中,我们可以省略后面的泛型,因为它可以进行类型的自动推断:

Set set = newHashSet<>;

在jdk9中,我们还能够对集合进行如下编写:

Set set = newHashSet<>{};

这行代码的意思是创建一个继承于HashSet的匿名子类对象,它将与Set共同使用泛型,那么这样有什么好处呢?

好处在于当你需要改造Set中的某个方法时,能够很方便地实现,比如:

publicstaticvoidmain(String[] args){

Set set = newHashSet<>{

@Override

publicbooleanadd(String s){

returnsuper.add(s + "--");

}

};

set.add( "zhangsan");

set.add( "lisi");

set.add( "wangwu");

for(String str : set) {

System.out.println(str);

}

}

运行结果:

wangwu--

zhangsan--

lisi--

异常处理

对于IO流的异常处理一直为人所诟病,传统的异常处理过程如下:

FileInputStream in = null;

try{

in = newFileInputStream( "");

} catch(FileNotFoundException e) {

e.printStackTrace;

} finally{

if(in != null){

try{

in.close;

} catch(IOException e) {

e.printStackTrace;

}

}

}

可以看到代码非常的臃肿,在jdk8中,我们还有另外一套解决方案:

try(FileInputStream in = newFileInputStream( "")) {

in.close;

} catch(IOException e) {

e.printStackTrace;

}

将资源放在try 语句的括号内,我们就不需要手动去关闭流资源了。

而在jdk9中,我们可以在try 中调用已经实例化的资源对象:

InputStreamReader reader = newInputStreamReader(System.in);

try(reader) {

reader.read;

} catch(IOException e) {

e.printStackTrace;

}

这种方式在jdk9之前是不支持的。

下划线的使用限制

在jdk8中,下划线是可以单独作为变量名进行定义的:

int_ = 100;

而jdk9中禁止了这种变量的定义:

d0da2df2228b9c4d5ea9d9735c900892.png

前言String存储结构的变化

在jdk8中,字符串的底层采用的是char数组:

5c0cecca54c2aa4146e9fcdf122110e7.png

而在jdk9中,它不再使用char数组实现,取而代之的是byte数组:

e12c3564bf9f9d9c685c2f8986165ec2.png

因为在UTF-16编码中,一个字符会占用两个字节,而大部分情况下,开发者使用的String中包含了较多的字母和数字,它们均只用一个字节就能够存储,所以采用char数组存储字符串会造成大量资源的浪费,为此,jdk9中特别设计了String的实现,将其底层改为了byte数组。

只读集合

jdk8中提供了unmodifiableList 方法来将一个集合转变为只读集合:

publicstaticvoidmain(String[] args){

List list = newArrayList<>;

list.add( "a");

list.add( "b");

list.add( "c");

List readList = Collections.unmodifiableList(list);

// 只读集合不允许添加元素

// readList.add("d");

readList.forEach(System.out::println);

}

若是想创建只读的Set集合,只需修改方法名即可:

publicstaticvoidmain(String[] args){

Set set = Collections.unmodifiableSet( newHashSet<>(Arrays.asList( 1, 2, 3, 4, 5)));

set.forEach(System.out::println);

}

只读的map集合也是如此:

publicstaticvoidmain(String[] args){

Map map = Collections.unmodifiableMap( newHashMap<> {

{

put( "zhangsan", 20);

put( "lisi", 21);

put( "wangwu", 22);

}

});

map.forEach((k,v) -> System.out.println(k + ":"+ v));

}

注意这里使用到了jdk9中的另一新特性来初始化Map集合,这在集合中的泛型 已经介绍过了。

以上均是jdk8中创建只读集合的方式,在jdk9中,它的创建方式只会更加简单:

publicstaticvoidmain(String[] args){

List list = List.of( 1, 2, 3, 4, 5);

list.forEach(System.out::println);

}

通过of 方法创建的集合它就是一个只读集合,是不可以再对其进行修改的。

然后是Set集合和Map集合:

publicstaticvoidmain(String[] args){

//创建只读Set

Set set = Set.of( 1, 2, 3, 4);

//创建只读Map

Map map = Map.of( "zhangsan", 20, "lisi", 21, "wangwu", 22);

//创建只读Map的第二种方式

Map map = Map.ofEntries(Map.entry( "zhangsan", 20), Map.entry( "lisi", 21));

}

Stream的增强

首先是takeWhile 方法:

publicstaticvoidmain(String[] args){

// takeWhile

List list = Arrays.asList( 1, 3, 2, 5, 4);

Stream stream = list.stream;

Stream newStream = stream.takeWhile(x -> x < 3);

newStream.forEach(System.out::println);

}

在该场景中, takeWhile 方法的作用是从集合第一个元素开始查找小于3的元素,第一个元素1小于3;第二个元素3不小于3,此时后面的所有元素都会被舍弃,所以运行结果为:

1

其次是dropWhile 方法:

publicstaticvoidmain(String[] args){

// dropWhile

List list = Arrays.asList( 1, 3, 2, 5, 4);

Stream stream = list.stream;

Stream newStream = stream.dropWhile(x -> x < 3);

newStream.forEach(System.out::println);

}

在该场景中, dropWhile 方法的作用是从集合第一个元素开始查找小于3的元素,第一个元素1小于3,会被舍弃;第二个元素3不小于3,此时后面的所有元素都被保留,所以运行结果为:

3

2

5

4

最后是ofNullable 方法,它允许Stream中存放单个null值:

publicstaticvoidmain(String[] args){

//ofNullable

Stream stream = Stream.ofNullable( null);

System.out.println(stream.count);

}

这样是没有任何错误的,运行结果为:

0

HttpClient

jdk9中提供了HttpClient来实现网络连接,用法如下:

publicstaticvoidmain(String[] args)throwsIOException, InterruptedException{

HttpClient client = HttpClient.newHttpClient;

HttpRequest request = HttpRequest.newBuilder(URI.create( "http://www.baidu.com")).GET.build;

HttpResponse response = client.send(request, HttpResponse.BodyHandler.asString);

System.out.println(response.statusCode);

System.out.println(response.version.name);

System.out.println(response.body);

}

运行结果:

200

HTTP_1_1

......

前言Java编译工具的升级

jdk9中升级了java的编译工具,它提供了sjavac 指令用于在多核处理器情况下提升jdk的编译速度。

本文作者:汪伟俊 为Java技术迷专栏作者 投稿,未经允许请勿转载。

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值