[Java] `JDK17` 模式变量 `Pattern variable` Variable ‘request‘ can be replaced with pattern variable

简介: [Java] `JDK17` 模式变量 `Pattern variable` Variable ‘request‘ can be replaced with pattern variable

缘起

起初是在项目中写了一段代码报了黄线

if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            HttpHeaders headers = request.headers();
            if (headers.isEmpty()) {
                ctx.channel().close();
                return;
            }
            ...
    }

这看到黄线,不能忍啊,点一下哎

不点不知道,点了一下,咦代码确实变好看了一点,就知道刚学学新技术了~

探寻

oracle

Pattern matching involves testing whether an object has a particular structure, then extracting data from that object if there’s a match. You can already do this with Java; however, pattern matching introduces new language enhancements that enable you to conditionally extract data from objects with code that’s more concise and robust.

模式匹配包括测试对象是否具有特定的结构,如果存在匹配,则从该对象中提取数据。你已经可以用Java做到这一点。但是,模式匹配引入了新的语言增强功能,使您能够有条件地使用更简洁和健壮的代码从对象中提取数据。

Pattern Matching for the instanceof Operator

Enhance the Java programming language with pattern matching for the instanceof operator. Pattern matching allows common logic in a program, namely the conditional extraction of components from objects, to be expressed more concisely and safely.

使用instanceof操作符的模式匹配增强Java编程语言。模式匹配允许程序中的公共逻辑,即从对象中有条件地提取组件,以更简洁和安全的方式表达。

为什么引入

在项目开发过程中,我们经常会写以下类似代码,臃肿而难看。这段代码主要是进行类型判断,然后进行类型转换。

if (obj instanceof String) {
    String s = (String) obj;    // grr...
    ...
}
  • 引入模版变量之后

A pattern is a combination of (1) a predicate, or test, that can be applied to a target, and (2) a set of local variables, known as pattern variables, that are extracted from the target only if the predicate successfully applies to it.

A type pattern consists of a predicate that specifies a type, along with a single pattern variable.

The instanceof operator (JLS 15.20.2) is extended to take a type pattern instead of just a type.

模式是(1)可以应用于目标的谓词或测试,以及(2)一组称为模式变量的局部变量的组合,只有当谓词成功地应用于目标时,这些局部变量才会从目标中提取出来。

类型模式由指定类型的谓词和单个模式变量组成。

instanceof操作符(JLS 15.20.2)被扩展为接受类型模式而不仅仅是类型。

if (obj instanceof String s) {
    // Let pattern matching do the work!
    ...
}

(In this code, the phrase String s is the type pattern.) The meaning is intuitive. The instanceof operator matches the target obj to the type pattern as follows: If obj is an instance of String, then it is cast to String and the value is assigned to the variable s.

Rather than using a coarse approximation for the scope of pattern variables, pattern variables instead use the concept of flow scoping. A pattern variable is only in scope where the compiler can deduce that the pattern has definitely matched and the variable will have been assigned a value. This analysis is flow sensitive and works in a similar way to existing flow analyses such as definite assignment.

如果断言失败 obj 不是 String 则不会为 s 赋值。

纸上得来终觉浅

if (a instanceof Point p) {
    // p is in scope
    ...
}
// p not in scope here
if (b instanceof Point p) {     // Sure!
        ...
}
if (obj instanceof String s && s.length() > 5) {
    flag = s.contains("jdk");
}
if (obj instanceof String s || s.length() > 5) {    
  // Error!
    ...
}

使用模版变量重构 effective java部分例子

public final boolean equals(Object o) {
    return (o instanceof CaseInsensitiveString) 
      && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}
  • 重构后
public final boolean equals(Object o) {
    return (o instanceof CaseInsensitiveString cis) 
      && cis.s.equalsIgnoreCase(s);
}

Pattern Matching for switch Expressions and Statements

概括

switch 通过表达式和语句的模式匹配以及模式语言的扩展来增强 Java 编程语言。扩展模式匹配switch允许针对多个模式测试表达式,每个模式都有一个特定的操作,以便可以简洁、安全地表达复杂的面向数据的查询。这是JDK 17 中的预览语言功能

目标

  • switch通过允许模式出现在标签中来扩展表达式和语句的表现力和适用性case
  • switch在需要时允许放松历史上的零敌意。
  • 引入两种新的模式:受保护的模式,允许使用任意布尔表达式来细化模式匹配逻辑,以及 括号模式,以解决一些解析歧义。
  • 确保所有现有switch表达式和语句继续编译而不进行任何更改并以相同的语义执行。
  • 不要引入switch与传统switch 构造分离的具有模式匹配语义的新的类似表达式或语句。
  • switch当 case 标签是模式时与 case 标签是传统常量时,不要使表达式或语句的行为有所不同。

直接看引入前后的对比

static String formatter(Object o) {
    String formatted = "unknown";
    if (o instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (o instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (o instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (o instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;
}
  • 引入 switch 增强之后
static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();
    };
}
jdk8
int dayOfWeek = 3;
String dayName;
switch (dayOfWeek) {
    case 1:
        dayName = "Monday";
        break;
    case 2:
        dayName = "Tuesday";
        break;
    case 3:
        dayName = "Wednesday";
        break;
    case 4:
        dayName = "Thursday";
        break;
    case 5:
        dayName = "Friday";
        break;
    case 6:
        dayName = "Saturday";
        break;
    case 7:
        dayName = "Sunday";
        break;
    default:
        dayName = "Invalid day";
        break;
}
System.out.println("Day of the week: " + dayName);
jdk17
int dayOfWeek = 3;
String dayName = switch (dayOfWeek) {
    case 1 -> "Monday";
    case 2 -> "Tuesday";
    case 3 -> "Wednesday";
    case 4 -> "Thursday";
    case 5 -> "Friday";
    case 6 -> "Saturday";
    case 7 -> "Sunday";
    default -> "Invalid day";
};
System.out.println("Day of the week: " + dayName);

总结

拥抱新技术,用就对了~

相关文章
|
10天前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
1月前
|
Java 编译器
java“变量 x 可能未被初始化”解决
在Java中,如果编译器检测到变量可能在使用前未被初始化,会报“变量 x 可能未被初始化”的错误。解决方法包括:1. 在声明变量时直接初始化;2. 确保所有可能的执行路径都能对变量进行初始化。
|
2月前
|
存储 Java
java基础(7)变量以及变量的分类
Java变量是内存中存储数据的基本单元,包含数据类型、名称和字面值。变量的数据类型决定了分配的内存空间大小。变量声明格式为“数据类型 变量名;”,变量名应符合标识符命名规范。变量可以重新赋值,但数据类型需一致。变量可以一行声明多个,作用域决定了变量的可用范围。变量分为局部变量和成员变量,局部变量定义在方法体内,成员变量定义在方法体外、类体内。
41 2
|
2月前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
62 2
|
18天前
|
Java 编译器
Java重复定义变量详解
这段对话讨论了Java中变量作用域和重复定义的问题。学生提问为何不能重复定义变量导致编译错误,老师通过多个示例解释了编译器如何区分不同作用域内的变量,包括局部变量、成员变量和静态变量,并说明了使用`this`关键字和类名来区分变量的方法。最终,学生理解了编译器在逻辑层面检查变量定义的问题。
Java重复定义变量详解
|
26天前
|
Java
通过Java代码解释成员变量(实例变量)和局部变量的区别
本文通过一个Java示例,详细解释了成员变量(实例变量)和局部变量的区别。成员变量属于类的一部分,每个对象有独立的副本;局部变量则在方法或代码块内部声明,作用范围仅限于此。示例代码展示了如何在类中声明和使用这两种变量。
|
1月前
|
缓存 Java Maven
java: 警告: 源发行版 11 需要目标发行版 11 无效的目标发行版: 11 jdk版本不符,项目jdk版本为其他版本
如何解决Java项目中因JDK版本不匹配导致的编译错误,包括修改`pom.xml`文件、调整项目结构、设置Maven和JDK版本,以及清理缓存和重启IDEA。
48 1
java: 警告: 源发行版 11 需要目标发行版 11 无效的目标发行版: 11 jdk版本不符,项目jdk版本为其他版本
|
25天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
23 0
[Java]静态代理与动态代理(基于JDK1.8)
|
1月前
|
Java
Java基础之 JDK8 HashMap 源码分析(中间写出与JDK7的区别)
这篇文章详细分析了Java中HashMap的源码,包括JDK8与JDK7的区别、构造函数、put和get方法的实现,以及位运算法的应用,并讨论了JDK8中的优化,如链表转红黑树的阈值和扩容机制。
25 1
|
1月前
|
分布式计算 资源调度 Hadoop
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
大数据-01-基础环境搭建 超详细 Hadoop Java 环境变量 3节点云服务器 2C4G XML 集群配置 HDFS Yarn MapRedece
77 4