Java8到Java17之间的主要特性描述

news2024/11/16 23:52:31

Java8到Java17之间的主要特性描述

文章目录

  • Java8到Java17之间的主要特性描述
    • Java8
      • lambda表达式与Stream API
      • 方法引用(Method Reference)
      • 接口默认方法(Default Methods)
      • 类型注解(Type Annotations)
      • 可重复注解(Repeating Annotations)
    • Java9
      • Java模块化(Java Module System)
      • 带有内部匿名类的菱形语法(Diamond Syntax with Inner Anonymous Classes)
      • 私有接口方法(Private Interface Methods)
    • Java10
      • 局部变量类型推断(Local Variable Type Inference)
    • Java11
      • Lambda表达式中的局部变量类型推断(Local Variable Type in Lambda Expressions)
    • Java14
      • Switch表达式(Switch Expressions)
    • Java15
      • 文本块(Text Blocks)
    • Java16
      • instanceof 模式匹配(Pattern Matching of instanceof)
      • 档案类(Records)
    • Java17
      • 封闭类(Sealed Classes)

Java8

主要特性:

  1. lambda表达式与Stream API(Lambda Expression and Stream API)
  2. 方法引用(Method Reference)
  3. 接口默认方法(Default Methods)
  4. 类型注解(Type Annotations)
  5. 可重复注解(Repeating Annotations)
  6. 方法参数反射(Method Parameter Reflection)

lambda表达式与Stream API

一般集合数据的处理示例:

public List<Car> findCheapCar(List<Car> cars) {
    List<Car> result = new ArrayList<>();
    for (Car car : cars) {
        if (car.getPrice() < 50000) {
            result.add(car);
        }
    }
    return result;
}

lambda表达式与Stream API搭配的示例:

public List<Car> findCheapCar(List<Car> cars) {
    return cars.stream().filter(car -> car.getPrice() < 50000)
		.collect(Collectors.toList());
}

通过调用stream()方法将集合类型的cars变量转换为stream,内部通过filter()方法设定对应的过滤条件,最后通过colletct()方法将最后的结果集包装为List返回。

方法引用(Method Reference)

一般lambda中引用方法示例:

public List<String> mapCarName(List<Car> cars) {
    return cars.stream().map(car -> car.getName())
		.collect(Collectors.toList());
}

方法引用使得代码更加简洁并且可读性更好,使用两个冒号::来引用方法:

public List<String> mapCarName(List<Car> cars) {
    return cars.stream().map(Car::toString)
		.collect(Collectors.toList());
}

接口默认方法(Default Methods)

当一个接口新增了方法,又不希望调用方端有任何感知。这时候,就可以使用接口默认方法(Default Methods)

来实现这个功能。

public interface IElectricCar {
    void charge();
}

public class BYD implements IElectricCar {
    @Override
    public void charge() {
        System.out.println("比亚迪开始充电了");
    }
}

添加一个新方法到接口中:

public interface IElectricCar {
    void charge();
    void charge(Date date);
}

这时候IElectricCar接口所有实现类都会出现编译报错:

Class 'BYD' must either be declared abstract 
or implement abstract method 'charge(Date)' in 'IElectricCar'

接口默认方法可以使用关键词default在接口中默认实现方法解决这个问题:

public interface IElectricCar {
    void charge();
    default void charge(Date date) {
        System.out.println(date.toString() + ":比亚迪开始充电了");
    }
}

类型注解(Type Annotations)

Field.getAnnotations()是用来获取Target为ElementType.FIELD的注解;

Field.getAnnotatedType().getAnnotations()用来获取Target为ElementType.TYPE_USE的注解,即类型注解。

类型注解可以在使用类型的任意地方使用它们,使用场景包括但不限于:

  • 本地变量定义
public static void main(String[] args) {
    @NotNull String userName = args[0];
}
  • 构造器调用
public static void main(String[] args) {
	List<String> request = new @NotEmpty ArrayList<>(Arrays.stream(args)
		.collect(Collectors.toList()));
}
  • 泛型
public static void main(String[] args) {
    List<@Email String> emails;
}

可重复注解(Repeating Annotations)

创建可重复注解

@Repeatable(Notifications.class)
public @interface Notify {
    String phone();
}

public @interface Notifications {
    Notify[] value();
}

在普通注解@Notify上增加了@Repeatable元注解,说明将@Notify注解当做@Notifications注解的对象数组元素来使用。

使用可重复注解

@Notify(phone = "15880000000")
@Notify(phone = "18900000000")
public class expressTimeoutException extends RuntimeException {
    final String username;
    public expressTimeoutException(String username) {
        this.username = username;
    }
}

Java9

主要特性:

  1. Java模块化(Java Module System)
  2. 带有内部匿名类的菱形语法(Diamond Syntax with Inner Anonymous Classes)
  3. 私有接口方法(Private Interface Methods)

Java模块化(Java Module System)

模块化是一组包(package)以及包的依赖与资源,相对于包而言,它提供了更加广泛的功能。

模块的是通过module-info.java进行定义,编译后打包后,就成为一个模块的实体;在模块的定义文件中,我

们需要指定模块之间的依赖靠关系,可以exports给那些模块用,需要使用那些模块requires

模块声明文件通常放置在模块源码的根目录:

# 声明
module com.foo.bar {
    requires org.baz.qux;
	exports com.foo.bar.alpha;
	exports com.foo.bar.beta;
}
# 位置
module-info.java
com/foo/bar/alpha/AlphaFactory.java
com/foo/bar/alpha/Alpha.java

模块之间的关系被称作可读性(readability),代表一个模块是否可以找到这个模块文件,并且读入系统中(注

意:并非代表可以访问其中的类型)。在实际的代码,一个类型对于另外一个类型的调用,我们称之为可访问性

(Accessible),这意味着可以使用这个类型;可访问性的前提是可读性,换句话说,现有模块可读,然后再进

一步检测可访问性(安全)。在Java9中,Public不再意味着任意的可访问性。

transitive可以可以提供一个间接可读性:

间接引用

带有内部匿名类的菱形语法(Diamond Syntax with Inner Anonymous Classes)

在Java9之前不能在匿名内部类中使用<>操作符,如下面代码示例:

public static abstract class StringAppender<T> {
    public abstract T append(String a, String b);
}

public static void main(String[] args) {
	StringAppender<String> appending = new StringAppender<>() {
        @Override
        public String append(String a, String b) {
            return new StringBuilder(a).append("-").append(b).toString();
        }
    };
}

在Java8中,会出现编译错误:

'<>' cannot be used with anonymous classes
#无法推断StringAppender<T>的泛型,必须指定<String>

将环境切换为Java9能正确编译通过。

私有接口方法(Private Interface Methods)

在Java9中可以在接口中定义私有方法,私有方法的主要目的在于通用方法的封装以提升其在别的默认方法中的可复用性。

public static void main(String[] args) {
    TestingNames names = new TestingNames();
    System.out.println(names.fetchInitialData());
}

public static class TestingNames implements NamesInterface {
    public TestingNames() {
    }
}

public interface NamesInterface {
    default List<String> fetchInitialData() {
        try (BufferedReader br = new BufferedReader(
            new InputStreamReader(this.getClass().getResourceAsStream("/names.txt")))) {
            return readNames(br);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private List<String> readNames(BufferedReader br) throws IOException {
        ArrayList<String> names = new ArrayList<>();
        String name = null;
        while ((name = br.readLine()) != null) {
            names.add(name);
        }
        return names;
    }
}

Java10

局部变量类型推断(Local Variable Type Inference)

Java需要在局部变量中显式地定义类型,代码显得非常冗余。Java10中的var类型允许省略语句左侧的类型声明,使得语句干练简洁。

Java10前的旧写法:

public static void main(String[] args) {
    Person Roland = new Person("Roland", "Deschain");
    Person Susan = new Person("Susan", "Delgado");
    Person Eddie = new Person("Eddie", "Dean");
    Person Detta = new Person("Detta", "Walker");
    Person Jake = new Person("Jake", "Chambers");

    List<Person> persons = List.of(Roland, Susan, Eddie, Detta, Jake);
    for (Person person : persons) {
        System.out.println(person.name + " - " + person.lastname);
    }
}

使用var后的写法:

public static void main(String[] args) {
    var Roland = new Person("Roland", "Deschain");
    var Susan = new Person("Susan", "Delgado");
    var Eddie = new Person("Eddie", "Dean");
    var Detta = new Person("Detta", "Walker");
    var Jake = new Person("Jake", "Chambers");

    var persons = List.of(Roland, Susan, Eddie, Detta, Jake);
    for (var person : persons) {
        System.out.println(person.name + " - " + person.lastname);
    }
}

Java11

Lambda表达式中的局部变量类型推断(Local Variable Type in Lambda Expressions)

在Java11中针对Java10中的局部变量类型推断这个特性进行了改善,可以在lambda表达式中使用var进行类型推断而不是进行明确的类型声明。

public static void main(String[] args) {
    var Roland = new Person("Roland", "Deschain");
    var Susan = new Person("Susan", "Delgado");
    var Eddie = new Person("Eddie", "Dean");
    var Detta = new Person("Detta", "Walker");
    var Jake = new Person("Jake", "Chambers");

    var filteredPersons = List.of(Roland, Susan, Eddie, Detta, Jake).stream()
        .filter((var x) -> x.name.contains("a"))
        .collect(Collectors.toList());
    System.out.println(filteredPersons);
}

Java14

Switch表达式(Switch Expressions)

Java14前的旧写法:

public static void main(String[] args) {
    int days = 0;
    Month month = Month.APRIL;

    switch (month) {
        case JANUARY:
        case MARCH:
        case MAY:
        case JULY:
        case AUGUST:
        case OCTOBER:
        case DECEMBER:
            days = 31;
            break;
        case FEBRUARY :
            days = 28;
            break;
        case APRIL:
        case JUNE:
        case SEPTEMBER:
        case NOVEMBER:
            days = 30;
            break;
        default:
            throw new IllegalStateException();
    }
}

Java14的新写法:

public static void main(String[] args) {
    int days = 0;
    Month month = Month.APRIL;

    days = switch (month) {
        case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER :
            days = 31;
            break;
        case FEBRUARY :
            days = 28;
            break;
        case APRIL, JUNE, SEPTEMBER, NOVEMBER :
            days = 30;
            break;
        default:
            throw new IllegalStateException();
    }
}

使用箭头标识符(->)改造后的写法:

public static void main(String[] args) {
    int days = 0;
    Month month = Month.APRIL;

    days = switch (month) {
        case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> 31;
        case FEBRUARY -> 28;
        case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
        default -> throw new IllegalStateException();
    };
}

在case块中,java14使用了箭头标识符(->)替代冒号(:),即使没有break关键字,也会在匹配到的第一个case分支后跳出switch语句。

yield关键字配合箭头标识符(->)可以处理更复杂逻辑:

public static void main(String[] args) {
    int days = 0;
    Month month = Month.APRIL;

    days = switch (month) {
        case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> {
            System.out.println(month);
            yield 31;
        }
        case FEBRUARY -> {
            System.out.println(month);
            yield 28;
        }
        case APRIL, JUNE, SEPTEMBER, NOVEMBER -> {
            System.out.println(month);
            yield 30;
        }
        default -> throw new IllegalStateException();
    };
}

Java15

文本块(Text Blocks)

文本块可以理解为对格式化字符串的一个优化操作,从Java15允许编写一个跨越多行的字符串作为常规文本。相

比于在Java15之前,跨多行需要使用"+"号进行多行字符串拼接,会更加的方便并且可读性更高。

Java15之前,需要人为的保证字符串的格式化操作:

public static void main(String[] args) {
    System.out.println(
        "<!DOCTYPE html>\n" +
        "<html>\n" +
        "     <head>\n" +
        "        <title>Example</title>\n" +
        "    </head>\n" +
        "    <body>\n" +
        "        <p>This is an example of a simple HTML " +
        "		page with one paragraph.</p>\n" +
        "    </body>\n" +
        "</html>\n");
}

Java15使用Text Blocks之后:

public static void main(String[] args) {
    System.out.println(
        """
        <!DOCTYPE html>
        <html>
        	<head>
        		<title>Example</title>
        	</head>
            <body>
            	<p>This is an example of a simple HTML 
            	page with one paragraph.</p>
            </body>
        </html>      
        """
    );
}

Java16

instanceof 模式匹配(Pattern Matching of instanceof)

instanceof模式匹配允许我们以内联形式转换变量,并在所需的if-else块中使用它而无需进行强转。

需要强转的旧写法:

public static double getPrice(Car car) {
    if (car instanceof BYD) {
        BYD byd = (BYD) car;
        return byd.getPrice();
    } else if (car instanceof Tesla) {
        Tesla tesla = (Tesla) car;
        return tesla.getPrice();
    } else throw new IllegalArgumentException();
}

使用模式匹配写法:

public static double getPrice(Car car) {
    if (car instanceof BYD byd) {
        return byd.getPrice();
    } else if (car instanceof Tesla tesla) {
        return tesla.getPrice();
    } else throw new IllegalArgumentException();
}

需要注意的是,对应的变量范围,只在当前所属的if-else代码块中可见。

档案类(Records)

档案类是用来表示不可变数据的透明载体,用来简化不可变数据的表达,提高编码效率,降低编码错误。

  • 档案类是个终极(final)类,其父类是父类是java.lang.Record。不支持继承,不能用任何其他类来继承它。没有子类,也就意味着我们不能通过修改子类来改变档案类;
  • 档案类允许实现接口;
  • 档案类声明的变量是不可变的变量;
  • 档案类不能声明可变的变量,也不能支持实例初始化的方法。这就保证了,我们只能使用档案类形式的构造方法,避免额外的初始化对可变性的影响;
  • 档案类不能声明本地(native)方法。如果允许了本地方法,也就意味着打开了修改不可变变量的后门。

老式的POJO定义:

public class Car {
    private String name;
    private double price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public Car(String name, String price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {}

    @Override
    public int hashCode() {}

    @Override
    public String toString() {}
}

在类名前使用关键词record定义为档案类,一行解决:

public record CarRecord(String name, double price) {}

Java17

封闭类(Sealed Classes)

类的final修饰符能禁止任何类继承它,Java17封闭类带来的全新特性,封闭类允许针对permit指定的类进行继承

扩展,除此之外,封闭类对于其它类而言,可以理解为是带有final修饰符的类。

public sealed class Car permits BYD, Tesla {}

permits关键字指定的子类必须要增加如下几种修饰符中的一种:

  • final:表示该类不能被继承
  • sealed:修饰类/接口,用来描述这个类/接口为密封类/接口
  • non-sealed:修饰类/接口,用来描述这个类/接口为非密封类/接口,显式放弃密封
  • permits:用在extends和implements之后,指定可以继承或实现的类

封闭类会带来相应的条件约束,包括:

  • Permitted 子类在编译期必须能够被封闭类访问
  • Permitted 子类必须直接继承封闭类
  • Permitted 子类必须有如下修饰符中的一个进行修饰:final,sealed,non-sealed
  • Permitted 子类必须在同一个java模块中
public final class BYD extends Car {}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/186955.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文看懂YOLO v8

2023年&#xff0c;YOLO系列已经迭代到v8&#xff0c;v8与v5均出自U神&#xff0c;为了方便理解&#xff0c;我们将通过与v5对比来讲解v8。想了解v5的可以参考文章yolov5。 首先&#xff0c;回归一下yolov5&#xff1a; Backbone&#xff1a;CSPDarkNet结构&#xff0c;主要结…

结构体的内存对齐规则

结构体的内存 一、对齐规则 1.数据成员对齐规则:结构(struct或联合union&#xff09;的数据成员&#xff0c;第一个成员在与结构体变量偏移量为0的地址处&#xff0c;以后每个数据成员存储的起始位置要从该成员大小的整数倍开始&#xff08;比如int在32位机为4字节&#xff0…

anaconda/python安装虚拟环境并安装特定版本的库文件

anaconda/python安装虚拟环境并安装特定版本的库文件 文章目录anaconda/python安装虚拟环境并安装特定版本的库文件python安装虚拟环境安装教程pycharm加载虚拟环境以及安装指定的库文件python安装虚拟环境 安装教程 安装主要的代码指令就是下面这一句: conda create -n Env…

金融风控10

深度学习与金融风控 反欺诈生命周期 第一层设备与网络 - 代理检测 - IDC检测 - 模拟器/虚拟机检测 - 木马检测 第二层用户行为 - 注册行为 - 登录行为 - 交易行为 - 事件行为 - 时间间隔异常 第三层业务频次 - 注册频次 - 登录频次 - 交易频次 - 地域频次 - …

计算机组成原理笔记记录(第二章)

次为笔记记录&#xff0c;原视频链接为B站视频链接&#xff0c;若有错误请指出&#xff0c;看到就会改正 进制 r进制数及其转换成十进制数 r^n就是第n位的维权,n<0就是小数部分的位权。 例子:1011 为十进制的时候:10111103010211011100 为二进制的时候 1011123022121120(10…

Scipy误差函数详解

文章目录误差函数简介复平面上的误差函数与误差函数相关的函数误差函数简介 误差函数的实质是正态分布的概率&#xff0c;其重要性可见一斑&#xff0c;其表达式为 erf⁡2π∫0xe−t2dt\operatorname{erf}\frac{2}{\sqrt{\pi}}\int^x_0e^{-t^2}\text dt erfπ​2​∫0x​e−t2…

vue老项目增加提交格式化功能[eslint+prettier+husky+lint-staged]

一、当前项目情况说明 当前项目是已经开发迭代很久的项目&#xff0c;之前因为需求紧急&#xff0c;所以没有对代码格式话进行规范要求&#xff0c;导致每个开发人员提交的代码格式千差万别&#xff0c;增加了阅读难度及后期的维护成本&#xff0c;如果直接run lint&#xff0…

网络拓扑七大类型:总线、环形、星形、网状、树形、点对点、混合,我背的滚瓜烂熟!

大家好&#xff0c;这里是网络技术联盟站。 在网络世界中&#xff0c;经常会看到各种各样的网络拓扑&#xff0c;网络拓扑主要就是描述网络中各个元素的对应关系&#xff0c;那么网络中包含哪些类型的拓扑呢&#xff1f; 如上图所示&#xff0c;网络拓扑一般有两大类型&#x…

JS---数组的方法

一、方法 1.1、Pushing和Poping arr.push(1)&#xff1a;往arr数组的最后面压入1&#xff0c;push() 方法返回新数组的长度。 var fruits ["Banana", "Orange", "Apple", "Mango"]; fruits.push("Kiwi"); // fruits …

Ruoyi-Cloud框架学习-【04 用户登录】

前端 路由配置在router/index.js里 首页在views/index.vue4 前端端口与后台端口在vue.config.js里定义 vue.config.js 前台端口 后台端口 Ruoyi-Cloud登录流程 Login.vue 定义了登录handlerlogin&#xff0c;具体方法调用modules/user.js store/index.js 调用了modul…

【Stm32杂谈】:Stm32F103野火指南针开发板红外遥控程序问题记录和解析(个人理解)

项目场景&#xff1a; 最近在使用Stm32F103野火指南针开发板开发红外遥控外设得时候&#xff0c;用得是野火得开发板&#xff0c;本来发现应该很简单的事情&#xff0c;官方也很贴切的提供了官方例程。但是居然有问题&#xff0c;无法正常使用。 于是这篇文章应运而生&#xff…

环保数采仪 5G无线环保数采仪 智能环保数采仪

计讯物联智能环保数采仪&#xff0c;无线远距离数据传输、采集、控制、存储。支持全网通5G/4G移动网络、北斗、有线通信&#xff0c;数据上报云监控中心&#xff0c;支持GPS定位分散设备远程统一管理。支持环保协议&#xff0c;对接各省市县级监管平台&#xff0c;广泛应用于废…

Kubernetes集群搭建

Kubernetes集群搭建 目录 前言前期准备K8S集群安装 虚拟机设置安装K8S集群k8s部署Nginx 附录1 Docker安装附录2 yum k8s 问题附录3 k8s start问题附录4 k8s master init附录5 node节点添加进集群失败&#xff0c;可以删除节点重新添加 前言 本文指定Docker与K8s版本&#xf…

DynaSLAM-3 DynaSLAM中Mask R-CNN部分源码解析(Ⅱ)

目录 1.FPN 1.1 FPN层原理 1.2 FPN代码解析 2. 候选框的生成 2.1 根据特征图生成候选框 1.FPN 1.1 FPN层原理 在Faster R-CNN网络中&#xff0c;提取特征的时候&#xff0c;将原始数据经过一系列的卷积层&#xff0c;我们只用最后一层的特征图进行提取。 比如五层卷积神经…

C++(36)-VS2019- 动态库调用

1.被调用的动态库 MyDll 2.调用的可执行文件 MyExe 源码实例链接&#xff1a;MFC-VS2019-EXE调用DLL-demo.zip-C代码类资源-CSDN下载 1.MyDll 1.1 MyDll头文件&#xff1a;MyDll.h 声明此动态库为导出动态库。 声明导出函数。 #pragma once#define MYDECLARE_PUB…

【05】FreeRTOS的中断管理

目录 1.什么是中断 2.中断优先级分组 2.1中断优先级分组-介绍 2.2中断优先级分组-配置 2.3中断优先级分组-特点 3.中断相关寄存器 3.1寄存器地址 3.2在FreeRTOS中配置PendSV和Systick中断优先级 3.3中断相关寄存器 4.FreeRTOS中断管理实验 4.1修改freertos_demo.c …

2023.1.30作业-【尝试移植TF-A】

1、解压源码&#xff0c;进入目录如图一 2、解压源码包 3、进入解压后的目录&#xff0c;打入官方补丁 4、查看SD卡的分区&#xff0c;发现正常无需重新分区 5、导入编译工具查看是否正常导入 6、添加设备树等相关文件 7、修改上层目录下的 Makefile.sdk中添加 stm32mp157a-fsm…

chatGPT模型简介

ChatGPT的工作原理 chatGPT 是一款由 OpenAI 开发的聊天机器人模型&#xff0c;它能够模拟人类的语言行为&#xff0c;与用户进行自然的交互。它的名称来源于它所使用的技术—— GPT-3架构&#xff0c;即生成式语言模型的第3代。 chatGPT的核心技术是 GPT-3 架构。它通过使用大…

vue 自动生成swagger接口请求文件

前端: vue-element-admin 后端: .net core (6.0) 找了很多自动生成的代码的&#xff0c;感觉不太行&#xff0c;可能是我不太懂。所以自己根据swagger.json去生成了js请求文件。 后端很简单&#xff0c;就不说了&#xff0c;只要能访问到swagger的地址就可以&#xff0c;主要…

【My Electronic Notes系列——低频功率放大器】

目录 序言&#xff1a; &#x1f3c6;&#x1f3c6;人生在世&#xff0c;成功并非易事&#xff0c;他需要破茧而出的决心&#xff0c;他需要永不放弃的信念&#xff0c;他需要水滴石穿的坚持&#xff0c;他需要自强不息的勇气&#xff0c;他需要无畏无惧的凛然。要想成功&…