java 9- java17 新特性

java 9 - java17新特性不包含预览版功能, 只包含正式版功能
java 9 - java17新特性不包含预览版功能, 只包含正式版功能
java 9 - java17新特性不包含预览版功能, 只包含正式版功能

Java 9

1. 模块化开发

首先, 这个模块机制可以不使用, 默认使用全部包`java.base`, 跟`java8`的使用是一样的,非必须品, 
  1. 模块机制
    在我们之前的开发中,不知道各位有没有发现一个问题,就是当我们导入一个jar 包作为依赖时(包括JDK官方库),实际上很多功能我们并不会用到,但是由于它们是属于同一个依赖捆绑在一起,这样就会导致我们可能只用到一部分内容,但是需要引用一个完整的类库,实际上我们可以把用不到的类库排除掉,大大降低依赖库的规模。
    在这里插入图片描述
  2. 在idea中的java项目中新建module-info.java
    module mode.a{ // 当前项目模块名, 名字随便改, 是唯一的, 一个项目中最多仅有一个module-info.java文件
    
    }
    
  3. 此时,在main方法中调用java.util.Logger类, 则无法访问,需要在module-info.java中添加以下代码即可使用
    module mode.a{
    	requires java.logging
    }
    

2. 反射限制

在java8之前, 反射随便用, 随便设置其中的内容, 而在java9中, 需要授权给其他包反射权限

  • 系统模块: 来自JDK和JRE的模块(官方提供的模块,比如我们上面用的),我们也可以直接使用 java --list-modules命令来列出所有的模块,不同的模块会导出不同的包供我们使用。
  • 应用程序模块: 我们自己写的Java模块项目。
  • 自动模块: 可能有些库并不是Java 9以上的模块项目,这种时候就需要做兼容了,默认情况下是直接导出所有的包,可以访问所有其他模块提供的类,不然之前版本的库就用不了了。
  • 未命名模块: 我们自己创建的一个Java项目,如果没有创建module-info.java,那么会按照未命名模块进行处理,未命名模块同样可以访问所有其他模块提供的类,这样我们之前写的Java 8代码才能正常地在Java 9以及之后的版本下运行。不过,由于没有使用Java 9的模块新特性,未命名模块只能默认暴露给其他未命名的模块和自动模块,应用程序模块无法访问这些类(实际上就是传统Java 8以下的编程模式,因为没有模块只需要导包就行)

例子: 假设 A 项目为公司common包, B项目为新开发项目,
1. A项目中使用java8方式,B项目不受任何影响,可以直接设置反射
2. A项目中使用java9模块化方式, B项目在module-info.java引入A项目包 , 则也是无法使用A项目的反射
3. 在上一条的前提下, A项目module-info.java需要关键字open 表示开放反射机制:

public interface Test{}

open module mode.a{ 
	requires static transitive java.logging
	exports com.test.entity to mode.b
	opens com.test.entity to mode.b
	uses com.test.Test
}

module mode.b{
	requires transitive java.logging
	requires mode.a
	// 声明B实现了A的这个接口
	provides com.test.Test with com.testB.TestImpl
}

关键字配置:

关键字介绍
open在开放模块中使用, 别的模块可以使用本模块中的类进行反射
requires导入那个包, 导入才能使用
static编译时通过, 不包含在打的包中
opens在开放包时使用, 别的模块只能反射这个包下的类
exports开放那个包,开放出去别的包才能使用
to指定当前包暴露给那个模块
transitive导出时依赖传递
uses指定接口需要实现
provides [interface] with [class]声明B实现了A的这个接口

3. Jshell 交互式编程

jShell跟 python的 那个交互式编程差不多

打开cmd, 输入jshell 即可使用, 就不多说了, 一般用不上

4. 接口中的私有方法

在java8中, 接口中新增了 default 方法, 接口中的方法都是默认public static
在java9中, 接口中新增了priavte方法, 此方法只有接口中的私有方法和默认方法可以调用

5. 集合类新增的工厂方法

Collections 下的List, Map等接口, 新增了of 方法, 此方法生成的对象时不可变得, 跟Arrays.asList()方法生成的List是一样的

Map.of(K1,V1,K2,V2,....) // 最大十组
List.of(O1, O2, O3 ....)
Set.of(O1, O2, O3 ....)

6. Stream Api 改进

java8中的新特性Stream 在java9中进行了改进

  1. 生成的null会报错

    Stream.of(E...) // java 8 生成stream流, E为null的话会报错,用下面的不会
    Stream.ofNullable(E...)// java 9
    
  2. iterate 迭代条件增强

    // java8
    Stream.iterate(0, i -> i++) // 第一个参数是种子初始化, 第二个参数是操作, 返回的类型和第一个参数相同
    		.limit(20); // 限制生成20个
    // java9
    Stream.iterate(0, i -> i<20, i -> i++) // 第一个参数是种子初始化, 第二个参数是截断的条件, 第三个参数是操作
    
  3. 截断操作

    Stream.iterate(0, i -> i<20, i -> i++) 
    	.takeWhile(i -> i < 10)  // 什么情况后面的全不要, 返回false,后面的都不要
    							// 结果: 0123456789
    	.dropWhile(i -> i < 10) // 什么情况下后面的全要, 返回false,后面的全要
    	
    							// [什么都没有, 因为第一个元素=0,所以直接截断了]
    

7 其他小型变动

  1. try-with-resource 优化
    此语法现在不需要完整声明一个变量, 可以直接将现有变量丢进去

    什么是try-with-resource, 他和 try-catch -finally有什么区别:

    // java 7  try-with-resource 写法,  在try()中的代码会在结束后调用close方法关闭
    try(Connetion conn = facter.newConnetion()){
    	conn.createChannel();
    }catch(Exception e){}
    
    // try-catch-finally  需要在结束后判断手动关闭
    Connetion  conn = null;
    try{
    	conn = facter.newConnetion();
    	conn.createChannel();
    }catch(Exception e){}
    finally{
    	if(conn != null){
    		conn.close();
    	}
    }
    
    // java 9 优化, 在第一种情况下, 如果try()中需要关闭的代码特别多, 则需要很多对象, 以下这种写法优化了
    Connetion  conn = facter.newConnetion();
    try(conn){
    	conn.createChannel();
    }catch(Exception e){
    
    }
    
  2. Optional 方法增加

    // 1. 判空分支
    // java8
    Optional.ofNullable(null)
    	.ifPresent( o -> o.toLowerCase())// 如果不为空则小写
    // java9
    Optional.ofNullable("")
    		.ifPresentOrElse( o -> o.toLowerCase(), // 如果不为空则小写
                            () -> System.out.println("obj is Null")); //为空则执行这段话
    
    // 2. or方法
    Optional.ofNullable(null).or(()-> Optional.of("123"))// 创建一个对象, 是空的话,替换成or中的对象
    // 3. stream
    Optional.ofNullable("").stream();
    
  3. 泛型匿名内部类型推断

    // java 8 此写法报错,   需要在new Test<String> 写好. java9则不需要
    Test<String> t = new Test<>("string"){
    	@Override
    	public String test(){
    		return t;
    	}
    };
    

Java 10

局部类型推断

  1. var关键字只能在局部变量中使用,并赋予初始值
  2. 他在编译完成后会变成具体的变量类型
  3. Stream中不支持 (java11支持)
public class A{
	String a = "a";
	var b = "b";// 此用法报错

	public void test(){
		String c = "c";
		var d = "d";
		var e; // 报错
		// c.equlse(d) == true;
	}
}

Java 11 TLS

java 11 是继 java8 后的又一个长期维护版本(TLS), 在java17出现前一直保持着广泛使用

1. Stream中的自动类型推断,

```java
// java 10
Consumer<String> con = (String str) ->{};
// java 11
Consumer<String> con = (var str) ->{};
```

2. String 类方法增强

  1. 判空 isBlank()
    	String str = "";
    	str.isBlank(); // 为 "" true 或者 "   "true
    	str.isEmpty(); // 为 "" true 或者 "   "false
    
  2. 根据\n分割字符串 lines()
    	String str ="A\nB";
    	String str2 = str.repeat();
    	str2 = ["A", "B"]
    
  3. 重复拼接 repeat(int)
    String str ="AB";
    str.repeat(2);
    // str == "ABAB" 
    
  4. 去除空格 strip()
    trim 和 strip 的区别:
    trim()可以去除字符串前后的半角空白字符
    strip()可以去除字符串前后的全角和半角空白字符
  • 半角是我们多数人在打字的时候使用的状态,如果我们不去刻意调整半全角,它会一直伴随着我们,因为半角状态下,人们已经习惯了这种打字模式,半角状态下可以使用任何标点符号,而且对于空格也没有特殊限制。unicode编码为\u0020。
  • 全角占两个字节,半角占一个字节。半角全角主要是针对标点符号来说的,全角标点占两个字节,半角占一个字节,而不管是半角还是全角,汉字都还是要占两个字节。unicode编码为\u3000。
String str = " ABC ";
str.strip(); // 去除前后空格 'ABC'
str.stripLeading(); // 去除前空格 'ABC '
str.stripTrailing(); // 去除后空格 ' ABC'

3. HTTPClient

使用步骤

  1. 创建HttpClient

     var client = HttpClient.newHttpClient();
    
  2. 创建HttpRequest

    var request = HttpRequset.newBuilder(URI.create("url")).build();
    // 这里的`url`需要按照实际的填写
    
  3. 发送请求

     var response = client.send(request, HttpResponse.BodyHandlers.ofString());
     // 第一个参数是request, 第二个参数是返回值的类型, 可以是string, 也可以是InputStream, File, ByteArray等
    
  4. 获取相应体

     var body = response.body();
    

以下代码是java11的一个demo , 下载美女图片的, 可以试试看
url: https://pic.netbian.com/4kmeinv/

    public static void main(String[] args) throws IOException, InterruptedException {
        var client = HttpClient.newHttpClient();
        var request = HttpRequest.newBuilder(URI.create("https://pic.netbian.com/4kmeinv/")).build();
        var send = client.send(request, HttpResponse.BodyHandlers.ofString());
        var body = send.body();
        var substring = body.substring(body.indexOf("<ul class=\"clearfix\">") + "<ul class=\"clearfix\">".length());
        var ul = substring.substring(0, substring.indexOf("</ul>"));
        ul = p.matcher(ul).replaceAll("");
        var split = ul.split("<li>");
        var collect = Arrays.stream(split).filter(StringUtils::isNotBlank).map(e -> {
            var substring1 = e.substring(e.indexOf("target=\"_blank\"><img src=\"") + "target=\"_blank\"><img src=\"".length());
            var substring2 = substring1.substring(0, substring1.indexOf("\" alt=\""));
            return "https://pic.netbian.com" + substring2;
        }).collect(Collectors.toList());
        for (var i = 0; i < collect.size(); i++) {
            var request1 = HttpRequest.newBuilder(URI.create(collect.get(i))).build();
            var send1 = client.send(request1, HttpResponse.BodyHandlers.ofInputStream());
            var inputStream = send1.body();
            var fileOutputStream = new FileOutputStream("D:\\img\\"+ i+".jpg");
            try(inputStream; fileOutputStream) {
                int size ;
                var data = new byte[1024];
                while ((size = inputStream.read(data))>0)
                {
                    fileOutputStream.write(data, 0 ,size);
                }
            } catch (IOException ex) {

            }
        }
    }

Java12 - Java16

1. switch 新语法

在 java 14以前, switch 都是以下写法

    public static String grad(int score){
        score = score/ 10;
        var grad = "";
        switch (score) {
            case 10:
            case 9:
                grad = "优秀";
                break;
            case 8:
            case 7:
            case 6:
                grad = "量好";
            default:
                grad = "不及格";
        }
        return grad;
    }

在 java14中, switch增强了, switch表达式:
在新版中, switch 需要涵盖所有可能, 并且拥有返回值, 如果一个选择中需要多行代码, 可以加入{}, 并且是以yield 返回, 而不是return

缺点: 不能进行区间匹配

    public static String grad(int score){
        score = score/ 10;
        String grad = switch (score) {
            case 10, 9 -> {
                System.out.println("asdf");
                yield "优秀";
            }
            case 8, 7, 6 -> 
	            yield "量好";
            default -> "不及格";
        };
        return grad;
    }

2. 文本块

在python中,有一个""" """符号, 在历史版本的java中, 只能写" \" \" "进行转义,在java15中, 增加了文本块的使用:

 String str = """
         asdf
         '"'"'"
         wqe'r"
         \n\r
         zxc"v
         <a href="http://www.baidu.com">百度</a>
         """;
 System.out.println(str);

在这里插入图片描述

3. instanceof 增强

java 16开始

	// java 16以前
	public void test(Object obj){
		if(obj instanceof User){
			User user = (User)obj;
			user.getName;
		}
	}

	// java16开始 在if判断中可以直接写类型相同时转换的局部变量
	public void test(Object obj){
		if(obj instanceof User user){
			user.getName;
		}
	}

4. 空指针异常

异常问题准确化, 看控制台,明确指出异常的对象为 “b”
在这里插入图片描述

5. 记录类型

在 java14中首次出场, java16中正式版本
记录类型本质上也是一个普通的类, 不过是final类型切继承自java.lang.Record抽象类, 他会在编译时编译出 public get,hashcode,equals,toString等方法, 可是没有set方法, 所以依靠set, get方法的bean类型转换可能会有问题, 可实现接口, 不能继承

public record test(
        String name,
        String pass
) {

// 默认拥有全参的构造函数, 不能编写其他形式的构造函数和set方法, 可以重写get和toString等其他方法

}
public void test(){
	test test = new test("张三","123");
	test.name();
	test.pass();
}

Java 17

Java 17作为新的LTS长期维护版本,我们来看看都更新了什么〈不包含预览特性,包括switch第二次增强,哈哈,果然还是强度不够,都连续加强两个版本了)

1. 密封类型 sealed

  1. sealed 表示此类是密封类搭配 permits 指定子类继承
  2. non-sealed 表示此类是开放的, 继承密封类后需要开放当前类使用
  3. final 表示此类是最终的,无法继承, 可以继承sealed密封类使其闭环 使用使其闭环

密封类型可以说是Java 17正式推出的又一重磅类型,它在Java 15首次提出并测试了两个版本。

在Java中,我们可以通过继承(extends关键字)来实现类的能力复用、扩展与增强。但有的时候,可能并不是所有的类我们都希望能够被继承。所以,我们需要对继承关系有一些限制的控制手段,而密封类的作用就是限制类的继承。

  1. 密封类型有以下要求:

    • 可以基于普通类、抽象类、接口,也可以是继承自其他接抽象类的子类或是实现其他接口的类等。
    • 必须有子类继承,且不能是匿名内部类或是lambda的形式。
    • sealed 写在原来final的位置,但是不能和final , non-sealed 关键字同时出现,只能选择其一。
    • 继承的子类必须显式标记为 final . sealed 或是non-sealed类型。
  2. 声明格式:

    public sealed [abstract] [class/interface] 类名 [extends 父类] [implements 接口] permits [子类, ...]{
    // 以前咋写现在还咋写
    }
    
  3. 实际上在之前我们如果不希望别人继承我们的类,可以直接添加final 关键字;

    public class final A{}
    

    这样有一个缺点,如果添加了final关键字,那么无论是谁,包括我们自己也是没办法实现继承的,但是现在我有一个需求, 只允许我们自己写的类继承A,但是不允许别人写的类继承A, 这时该昨写?在Java 17之前想要实现就很麻烦。

  4. 我们可以使用密封类型来实现这个功能:

    public sealed class A permits B,C{}// 需要多个可以继承则可以写多个 , 隔开
    
    // 必须是final  或者 sealed 指定类继承
    public [final|sealed] class B extends A{} // 这个允许
    
    public non-sealed class C extends A{} // 这个允许,但是整个体系从这里打破, 变成了缺口,却也更灵活
    
    public final class D extends A{} // 这个不行, A没有让D继承
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值