java8到java17的蜕变

https://blog.csdn.net/weixin_72388638/article/details/131691554

目录

一、前言

二、JAVA8

Lambda表达式

Stream API

创建方式

中间操作

终止操作

Optional类

三、JAVA9

模块机制

JShell交互式编程

 接口

新增集合工厂方法

四、JAVA10

局部变量类型判断

五、JAVA11

Lambda表达式补充

String方法的补充

全新的HttpClient 使用

六、JAVA12-16

新的switch语法

文本块

新的instanceof语法

空指针异常的改进

记录类型(record)

七、Java 17

密封类型(sealed关键字)

总结


一、前言

springboot3 最低dk17,java8估计要被弃用了

二、JAVA8

Lambda表达式

相当于匿名内部类的简写


  1. public void test() {

  2. Thread t1 = new Thread(()-> System.out.println("你好")); //lambda 表达式

  3. t1.start();

  4. }

规范:

        (名称)-> {代码语句,包括返回值}

        和匿名内部类不同,只支持接口,不支持抽象类

        接口有且只有一个抽象方法

        接口上有@FunctionalInterface 标识

自定义接口


  1. @FunctionalInterface

  2. public interface myBy {

  3. Integer getAdd(Integer a,Integer b);

  4. }

       

使用


  1. public void test02() {

  2. myBy myBy=(a,b)-> a+b; //实现接口

  3. System.out.println(myBy.getAdd(1,2));

  4. }

有现成的实现可以直接代替


  1. private static Integer Add(Integer a, Integer b){ //加法

  2. return a+b;

  3. }

  4. public void test02() {

  5. // myBy myBy=(a,b)-> a+b;

  6. myBy my=(OneTest::Add); //借用别人的实现方法

  7. System.out.println(myBy.getAdd(1,2));

  8. }

线程安全性,(十分局限,不允许对外部数据进行赋值操作)

错误案例


  1. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  2. Integer a=0;

  3. list.forEach(i->{

  4. a+=i; //请注意,这个写法是错误的,lambda表达式为了保证线程安全不允许对外部数据进行赋值操作,当前编译阶段就会报错

  5. });

  6. System.out.println(a);

Stream API

函数式编程

作用:对集合、数组操作

对比Collections(集合操作工具类),Arrays(数组操作工具类) :


  1. Collections和Arrays会改变原来的集合数据;

  2. Stream则不会,它会返回一个新的带有结果的Stream;

  3. 不想改变原有数据的情况下操作集合和数组可以使用Stream;

  4. 操作集合和数组建议使用这种方式,进一步减少被优化的可能,能少写for就少写一个

创建方式

  1. public void test012() {

  2. List list=Arrays.asList(1,23,456,12,678,23);

  3. // 顺序流 按元素顺序返回

  4. Stream stream1 = list.stream();

  5. // 并行流 ,同时取数据

  6. Stream stream2 = list.parallelStream();

  7. //数组类型

  8. int[] arr =new int[]{1,2,3,4,5};

  9. IntStream stream3 = Arrays.stream(arr);

  10. Stream integerStream = Stream.of(1, 2, 3, 4, 5);

  11. }

  12. //Math.random() 生成 [0,1)的 double数

  13. //生成10个数

  14. Stream.generate(Math::random).limit(10).forEach(System.out::println);

中间操作

数据过滤(filter)


  1. //数据过滤 保留大于10的数据

  2. // 当filter(e->{return true;}) 返回true才保留当前操作数据

  3. List list=Arrays.asList(1,23,456,9,12,678,23);

  4. list.stream().filter(e->e>10).forEach(System.out::println);

  5. //结果 23,456,12,678,23

截取片段(limit)


  1. List list=Arrays.asList(1,23,456,9,12,678,23);

  2. //获得前4条数据 结果 1,23,456,9

  3. list.stream().limit(4).forEach(System.out::println);

舍弃片段(skip)(截取片段 相反)


  1. List list=Arrays.asList(1,23,456,9,12,678,23);

  2. //丢弃前面4个数据,结果为12,678,23

  3. list.stream().skip(4).forEach(System.out::println);

去重(distinct)


  1. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  2. //去重 根据equals和hashCode, 结果为:1,23,456,9,12,678

  3. list.stream().distinct().forEach(System.out::println);

映射(map)

自定义操作

map(e->{return "结果"}) 和filter类似, 只是return是自定义的结果


  1. List list=Arrays.asList("aa","bb","cc","dd");

  2. // 还是操作数据 ,自定义操作数据,用来返回一些特定数据; str.toUpperCase()转化成大写

  3. // map(e->{return "结果"}) 和filter类似 只是return是自定义的结果

  4. //结果 AA,BB,CC,DD

  5. list.stream().map(str->str.toUpperCase()).forEach(System.out::println);

排序(sorted)


  1. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  2. // 自然排序 ,结果:1,1,9,9,12,23,23,23,456,678

  3. // 对类对象的排序需要实现 Comparable 接口

  4. list.stream().sorted().forEach(System.out::println);

  5. //自定义排序,即使是类对象也不用实现Comparable 接口

  6. //自定义排序结果为:687,456,23,23,23,12,9,9,1,1

  7. list.stream().sorted((a,b)->{

  8. return Integer.compare(b,a);

  9. })

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

终止操作

匹配与查找


  1. allMatch(lambda) 检查是所有元素满足条件

  2. anyMatch(lambda) 检查是否至少匹配一个元素

  3. noneMatch(lambda) 检查是否没有匹配的元素

  4. findFirst() 返回第一个元素

  5. findAny() 返回当前流中的任意元素

  6. count() 返回流元素的总个数

  7. max(Double::compare) 返回流中最大值

  8. min(Double::compare)返回流中最小值

  9. forEach(lambda) 内部迭代

匹配与查找示例:


  1. // 1、allMatch 验证是否全部元素满足条件

  2. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  3. // 是否全部元素大于 30;返回false,true;当前结果为false

  4. boolean b = list.stream().allMatch(e -> e > 30);

  5. System.out.println(b);

  6. //2、noneMatch 检查全部元素,是否全部不满足条件

  7. // 全部不满足条件为true

  8. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  9. // 判断全部元素是否没有0,结果为true

  10. boolean b1 = list.stream().noneMatch(e -> e == 0);

  11. System.out.println(b1);

  12. //3、findFirst 返回第一个元素

  13. // 当前结果为 1

  14. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  15. Optional first = list.stream().findFirst();

  16. System.out.println(first);

  17. // 4、 findAny 随机返回一个元素

  18. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  19. // ?? 有BUG? 每次都是同一个结果

  20. //Collections.shuffle(list); 还是洗牌好用

  21. Optional first = list.stream().findAny();

  22. System.out.println(first);

  23. //5、count 求元素总数

  24. // 结果为 10

  25. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  26. long count = list.stream().count();

  27. System.out.println(count);

  28. //5、max最大值 自然排列取右边值

  29. //最大值

  30. Optional max = list.stream().max(Double::compare);

  31. //Optional max = list.stream().max((a,b)->Double.compare(a,b));

  32. System.out.println(max.get());

  33. //6、最小值 自然排列取左边值

  34. Optional min = list.stream().min(Double::compare);

  35. //Optional min = list.stream().min((a,b)->Double.compare(a,b));

  36. System.out.println(min.get());

  37. //7、遍历

  38. // list.forEach(System.out::println); 集合自带了遍历

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

归约(reduce)


  1. // 计算结果,返回计算结果

  2. // 0初始值,lambda累加操作 (a是初始值也是下一次结果值当前初始值设置是0,b是索引为i的元素)

  3. //结果为1235

  4. Integer reduce = list.stream().reduce(0, (a, b) -> a + b);

收集(collect)

把结果转化为list或set等


  1. // 把结果转化为list

  2. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  3. List collect = list.stream().filter(e -> e > 10).collect(Collectors.toList());

  4. System.out.println(collect);

  5. //把结果转化为set

  6. List list=Arrays.asList(1,1,23,23,456,9,9,12,678,23);

  7. Set collect = list.stream().filter(e -> e > 10).collect(Collectors.toSet());

  8. System.out.println(collect);

Optional类

可以预防空指针异常,

有if(a!=null) 时就优先使用这个类;

可以将任何一个类包装进Optional类中

API方法:


  1. //创建

  2. Optional.of(A) // A必须非空,A为空会报错

  3. Optional.empty() //创建一个非空的Optional实例

  4. Optional.ofNullable(A) //A可以为空 ,A为空不会报错; 使用这个

  5. //返回数据

  6. Optional.ofNullable(A).get() 返回包装的A

  7. Optional.ofNullable(A).orElse(B) 当前A不为空就返回A,否则返回B,(A和B需要是同一个类型)

  8. Optional.ofNullable(A).orElseGet() 如果有值则返回,否则返回有接口实现提供的对象

  9. Optional.ofNullable(A).orElseThrow() 如果有值则将其返回,否则抛出由Supplier接口实现提供的异常

示例:


  1. // 如果A为空就返回B

  2. String A=null;

  3. String a = Optional.ofNullable(A).orElse("A为空");

  4. System.out.println(a);

  5. private static void hello(String str){

  6. Optional.ofNullable(str) //包装进入Optional,空的也会放入

  7. .ifPresent(i->{

  8. System.out.println(i); //打印

  9. });

  10. }

Optional不太方便,Lambda里面不能执行对外部属性执行赋值操作还是挺多限制的不如使用Objects.isNull(A)

三、JAVA9

模块机制

module-info.java文件


  1. //暴露出去

  2. module module.a {

  3. exports com.test;

  4. }

  5. // 只暴露给指定的模块

  6. module module.a {

  7. exports com.test to module.b;

  8. }

  9. //导入module.a 中暴露的内容

  10. module module.b {

  11. requires module.a;

  12. }

  13. //依赖的传递性

  14. module module.a {

  15. exports com.test;

  16. requires transitive java。logging; // 传递到引用的模块

  17. }

  18. //暴露出去,并且开放反射权限

  19. open module module.a {

  20. exports com.test;

  21. }

JShell交互式编程

 

接口

接口可以存在私有方法(私有方法必须要实现)

新增集合工厂方法


  1. public void test04() {

  2. Map map = Map.of("A", 1, "B", 2); //生成只读map

  3. List list = List.of(1, 2, 3, 4, 5); // 和Arrays.asList(1, 2, 3, 4, 5)一样,生成只读list

  4. //list.add(6); 错误 list是只读的

  5. System.out.println(map);

  6. }

四、JAVA10

局部变量类型判断

怎么变成js了,


  1. public void test05() {

  2. var a="hello,word"; // 只能定义在方法局部变量

  3. // var b; 错误,不能定义未赋值的变量

  4. System.out.println(a);

  5. }

五、JAVA11

Lambda表达式补充

内可以定义 var类型变量;

String方法的补充


  1. public void test06() {

  2. String str=" ";

  3. System.out.println(str.isEmpty()); // 判断内容是否为空(有空格也是false)

  4. System.out.println(str.isBlank()); //判断外形是否为空(肉眼观察,即使有空格也是true)

  5. // str.repeat(2) 重复拼接2次成新字符串

  6. // str.lines() 根据 \n分割

  7. //str.strip() 去除首位空格

  8. // str.stripLeading() 去除首部位空格

  9. // str.stripTrailing() 去除尾部空格

  10. }

全新的HttpClient 使用


  1. public void test07() throws URISyntaxException, IOException, InterruptedException {

  2. //创建

  3. HttpClient client=HttpClient.newHttpClient();

  4. //构建请求

  5. HttpRequest request = HttpRequest.newBuilder(new URI("https://www.baidu.com")).GET().build();

  6. HttpResponse send = client.send(request, HttpResponse.BodyHandlers.ofString());

  7. //发送请求

  8. System.out.println(send.body());

  9. }

六、JAVA12-16

新的switch语法

老方式


  1. private static String grade(int score){

  2. score/=10;

  3. String Gl="";

  4. switch (score){

  5. case 10:

  6. case 9:

  7. Gl="优秀";

  8. break;

  9. case 8:

  10. case 7:

  11. Gl="良好";

  12. break;

  13. case 6:

  14. Gl="及格";

  15. break;

  16. default:

  17. Gl="不及格";

  18. }

  19. return Gl;

  20. }

switch允许有返回值,不写break

为switch表达式


  1. private static String grade2(int score){

  2. score/=10;

  3. return switch (score){

  4. case 10,9->"优秀";

  5. case 8,7->"良好";

  6. case 6->"及格";

  7. default->"不及格";

  8. };

  9. }

返回值yield


  1. private static String grade2(int score){

  2. score/=10;

  3. return switch (score){

  4. case 10,9->{

  5. //可以执行其他逻辑

  6. System.out.println("优秀");

  7. yield "优秀";

  8. }

  9. case 8,7->"良好";

  10. case 6->"及格";

  11. default->"不及格";

  12. };

  13. }

文本块


  1. public void test09() {

  2. // 普通字符串

  3. String str="adbc\nsdawd";

  4. System.out.println(str);

  5. //文本块

  6. String str2=

  7. """

  8. 文本块内容:

  9. asaiddawjid

  10. "sdfsef"fsef

  11. mdkaslekf

  12. """;

  13. System.out.println(str2);

  14. }

新的instanceof语法


  1. 旧的用法

  2. a instanceof A

  3. true: a是A的实例或者 ,a是A类的后代

  4. 新补充:

  5. a instanceof A b

  6. 为true时候相当于多执行了一步 A b=(A)a

可以直接转化对应的类型


  1. //旧的写法

  2. @Override

  3. public boolean equals(Object obj) {

  4. if(obj ==this) return true;

  5. if (obj instanceof Student){

  6. Student test=(Student) obj;

  7. return test.name.equals(this.name);

  8. }

  9. return false;

  10. }

  11. //新写法省一行代码

  12. @Override

  13. public boolean equals(Object obj) {

  14. if(obj ==this) return true;

  15. if (obj instanceof Student test){ // ture时候把obj转化成 了(Student)test

  16. return test.name.equals(this.name);

  17. }

  18. return false;

  19. }

空指针异常的改进

这个特性应该最容易感知出来(笑~)

有空指针异常时候打印的错误信息明确的指出了哪个参数空指针异常

记录类型(record)

在编译时候自动编译出 get、hashcode、equals、toString等方法

支持实现接口,不支持继承(位置已经被占用)

内部不能定义成员变量


  1. //记录类型

  2. public record Account(String user,String pwd) {

  3. //private String adb; 错误,不能定义成员变量

  4. //定义方法

  5. public void Add(){

  6. System.out.println("调用Add");

  7. }

  8. }

  9. //使用

  10. public void test010() {

  11. Account account1=new Account("123","2334");

  12. account1.Add();

  13. System.out.println(account1);

  14. }

七、Java 17

密封类型(sealed关键字)

以前final修饰的类不能被继承

sealed 修饰的类可以定点继承,只允许指定的类继承

要求:


  1. 1、可以基于普通类、抽象类、接口也可以是继承自其他抽象类的子类或是实现其他接口的类等

  2. 2、必须有子类继承,且不能是匿名内部类或者是lambda的形式

  3. 3、sealed写在原来final的位置,但是不能和final、non-selaled关键字同时出现,只能选择其一

  4. 4、继承的子类必须标记为final、sealed、non-sealed类型

示例:


  1. //A类

  2. public sealed class A permits B {

  3. //只允许B继承A (且B需要是final或者sealed 修饰的)

  4. public String name;

  5. }

  6. //B类

  7. public non-sealed class B extends A {

  8. // B为final时候不允许其他类继承

  9. // B为sealed 允许指定类继承

  10. // B为B是non-sealed ,重新开放继承权限,使其他类可以继承B来间接继承A ,(关键字怎么还带个 - ,难看)

  11. }

  12. //C类

  13. public class C extends B{

  14. }

  15. // 测试

  16. public void test011() {

  17. A a=new A();

  18. B b=new B();

  19. C c=new C();

  20. //A是sealed ,B是non-sealed ,c依旧继承了A中name属性

  21. c.name="王";

  22. System.out.println(c.name);

  23. }

你可能感兴趣的:(Java,windows,linux,microsoft)