写点什么

Java 新特性完整指南:Switch 模式匹配

  • 2023-07-18
    北京
  • 本文字数:10257 字

    阅读完需:约 34 分钟

Java新特性完整指南:Switch模式匹配

Switch 语句由选择器表达式和包含 case 标签switch 块组成;对选择器表达式进行求值,并切换到与求值结果相匹配的 case 标签所对应的执行路径。


在原来 switch 语句中,case…:标签语法采用的是穿透语义(fall-through semantics)。Java 14 增加了对新标签语法case ...-> 的支持,该语法采用的是非穿透语义。


Java 14 还增加了对 switch 表达式的支持。Switch 表达式的计算结果为单个值。该版本还引入了yield语句,用于显式地生成一个值。


支持 switch 表达式(另有一篇文章进行了详细讨论)是指可以将 switch 用于需要表达式(如赋值语句)的实例。

问题


即使有了 Java 14 所做的功能增强,switch 语句的使用还是有一些限制:


  1. Switch 选择器表达式只支持特定类型,即基本整型数据类型byteshortcharint;对应的装箱形式ByteShortCharacterIntegerString类;枚举类型。

  2. Switch 选择器表达式的计算结果只能与常量做相等比较。在匹配 case 标签和常量值时只对一个值进行检查。

  3. null 值的处理方式与其他值不同。

  4. 错误处理方式不统一。

  5. 枚举的作用域不是很合理。

解决方案


为了克服这些限制,人们已经提出并实现了一种实用、便捷的解决方案:switch 语句模式匹配和表达式。这个解决方案解决了上面提到的所有问题。


Switch 模式匹配是在 JDK 17 中引入的,JDK 18、19 和 20 对其做了改进,JDK 21 最终将其完成。


模式匹配从以下几个方面克服了传统 switch 语句的局限性:


  1. 选择器表达式的类型可以是整型基本类型(不包括long类型),也可以是任何引用类型。

  2. 除了常量之外,case 标签还可以包含模式。不同于常量 case 标签只能应用于一个值,模式 case 标签可以应用于多个值。引入了一个新的 case 标签case p,其中p是一个模式。

  3. Case 标签可以包含null

  4. Case 标签后面有一个可选的when子句,可用于条件模式匹配或受保护模式匹配。带有 when 的 case 标签被称为受保护 case 标签。

  5. 枚举常量的 case 标签可以限定。当使用枚举常量时,选择器表达式不一定要是枚举类型。

  6. 引入MatchException,在模式匹配中实现更统一的错误处理。

  7. 传统的 switch 语句和穿透语义也支持模式匹配。模式匹配的一个好处是方便面向数据的编程,例如提高复杂数据查询的性能。

什么是模式匹配?


模式匹配是一个功能强大的特性,它扩展了程序中控制流结构的功能。除了可以匹配传统上支持的常量外,该特性还允许选择器表达式与多个模式进行匹配。Switch 语句的语义并没有变化;与 switch 选择器表达式的值进行匹配的 case 标签可能包含模式,如果选择器表达式的值与一个 case 标签模式匹配成功,就会选中控制流中那个 case 标签所对应的执行路径。唯一的增强是,选择器表达式既可以是基本整型(不包括 long 类型),也可以是任何引用类型。除了常量之外,case 标签还可以包含模式。此外,还有一个新增功能是,case 标签支持 null 和限定枚举常量。


以下是 switch 块中 switch 标签的语法:


SwitchLabel:  case CaseConstant { , CaseConstant }  case null [, default]  case Pattern  default
复制代码


模式匹配既可以用于具有穿透语义的传统case…:标签语法,也可以用于非穿透语义的case…->标签语法。尽管如此,必须注意的是,一个 switch 块不能同时使用这两种类型的 case 标签。


得益于这些修改,模式匹配让开发人员可以实现更复杂的控制流结构,为代码逻辑的处理提供了更丰富的方法。

环境设置


要运行本文中的示例代码,唯一的先决条件是安装 Java 20 或 Java 21。与 Java 20 相比,Java 21 只做了一项增强,即在 case 标签中支持限定枚举常量。可以通过以下命令查看 Java 版本:


java --versionjava version "20.0.1" 2023-04-18Java(TM) SE Runtime Environment (build 20.0.1+9-29)Java HotSpot(TM) 64-Bit Server VM (build 20.0.1+9-29, mixed mode, sharing)
复制代码


因为在 Java 20 中,switch 模式匹配是一个预览特性,所以必须使用以下语法运行javacjava命令:


javac --enable-preview --release 20 SampleClass.javajava --enable-preview  SampleClass
复制代码


但是,也可以使用源码启动器直接运行它,命令行如下:


java --source 20 --enable-preview Main.java
复制代码


还有一个jshell选项,但也需要启用预览功能:


jshell --enable-preview
复制代码

一个简单的模式匹配示例


我们从一个简单的模式匹配示例开始,其中,switch 表达式的选择器表达式类型是引用类型Collection ;case 标签包含case p形式的模式。


import java.util.Collection;import java.util.LinkedList;import java.util.Stack;import java.util.Vector;
public class SampleClass { static Object get(Collection c) {
return switch (c) { case Stack s -> s.pop(); case LinkedList l -> l.getFirst(); case Vector v -> v.lastElement(); default -> c; }; }
public static void main(String[] argv) {
var stack = new Stack<String>(); stack.push("firstStackItemAdded"); stack.push("secondStackItemAdded"); stack.push("thirdStackItemAdded");
var linkedList = new LinkedList<String>();
linkedList.add("firstLinkedListElementAdded"); linkedList.add("secondLinkedListElementAdded"); linkedList.add("thirdLinkedListElementAdded");
var vector = new Vector<String>();
vector.add("firstVectorElementAdded"); vector.add("secondVectorElementAdded"); vector.add("thirdVectorElementAdded");
System.out.println(get(stack)); System.out.println(get(linkedList)); System.out.println(get(vector)); }}
复制代码


编译并运行这个 Java 应用程序,输出如下:


thirdStackItemAddedfirstLinkedListElementAddedthirdVectorElementAdded
复制代码

模式匹配支持所有引用类型


在上面给出的示例中,选择器表达式的类型是Collection类类型。但是,选择器表达式的类型可以是任何引用类型。因此,case 标签模式可以是与选择器表达式的值兼容的任何引用类型。例如,下面是经过修改的SampleClass类,它使用了Object类型的选择器表达式,而 case 标签模式除了之前使用的StackLinkedListVector等引用类型外,还包括一个记录模式和一个数组引用类型的模式。


import java.util.LinkedList;import java.util.Stack;import java.util.Vector;
record CollectionType(Stack s, Vector v, LinkedList l) {}
public class SampleClass { static Object get(Object c) { return switch (c) { case CollectionType r -> r.toString(); case String[] arr -> arr.length; case Stack s -> s.pop(); case LinkedList l -> l.getFirst(); case Vector v -> v.lastElement(); default -> c; }; }
public static void main(String[] argv) {
var stack = new Stack<String>(); stack.push("firstStackItemAdded"); stack.push("secondStackItemAdded"); stack.push("thirdStackItemAdded");
var linkedList = new LinkedList<String>();
linkedList.add("firstLinkedListElementAdded"); linkedList.add("secondLinkedListElementAdded"); linkedList.add("thirdLinkedListElementAdded");
var vector = new Vector<String>();
vector.add("firstVectorElementAdded"); vector.add("secondVectorElementAdded"); vector.add("thirdVectorElementAdded");
var r = new CollectionType(stack, vector, linkedList); System.out.println(get(r)); String[] stringArray = {"a", "b", "c"};
System.out.println(get(stringArray)); System.out.println(get(stack)); System.out.println(get(linkedList)); System.out.println(get(vector));
}}
复制代码


这次的输出如下:


CollectionType[s=[firstStackItemAdded, secondStackItemAdded, thirdStackItemAdded], v=[firstVectorElementAdded, secondVectorElementAdded, thirdVectorElementAdded], l=[firstLinkedListElementAdded, secondLinkedListElementAdded, thirdLinkedListElementAdded]]3thirdStackItemAddedfirstLinkedListElementAddedthirdVectorElementAdded
复制代码

Null case 标签


传统上,如果选择器表达式的计算结果为空,则 switch 语句在运行时会抛出NullPointerException。选择器表达式为空不是编译时问题。下面这个简单的应用程序有一个匹配所有 case 标签的default ,我们通过它演示下选择器表达式为空如何导致运行时异常NullPointerException


import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { default -> c; }; }
public static void main(String[] argv) { get(null); }}
复制代码


我们可以在 switch 块外面显式地检测空值,并仅在值非空时执行 switch,但这涉及到添加 if-else 代码。在新的模式匹配特性中,Java 增加了对null的支持。下面这个应用程序中的 switch 语句使用case null来检测选择器表达式的值是否为空。


import java.util.Collection;
public class SampleClass { static void get(Collection c) {
switch (c) { case null -> System.out.println("Did you call the get with a null?"); default -> System.out.println("default"); } }
public static void main(String[] argv) { get(null); }}
复制代码


在运行时,应用程序输出如下:


你在调用get方法时使用了null参数?
复制代码


case null可以与case default合并,如下所示:


import java.util.Collection;
public class SampleClass { static void get(Collection c) { switch (c) { case null, default -> System.out.println("Did you call the get with a null?"); } }
public static void main(String[] argv) { get(null); }}
复制代码


但是,case null 不能与任何其他 case 标签合并。例如,下面的类将 case null 与一个模式为Stack s的 case 标签做了合并:


import java.util.Collection;import java.util.Stack;
public class SampleClass { static void get(Collection c) { switch (c) { case null, Stack s -> System.out.println("Did you call the get with a null?"); default -> System.out.println("default"); } }
public static void main(String[] args) { get(null); }}
复制代码


该类将产生如下编译时错误:


SampleClass.java:11: error: 非法case标签合并          case null, Stack s -> System.out.println("Did you call the get with a null?");
复制代码

带有 when 子句的受保护模式


有时,开发人员可能会使用与布尔表达式计算结果做匹配的条件式 case 标签模式。这时,when子句就派上用场了。该子句会计算布尔表达式,形成所谓的“受保护模式”。如下所示,代码中的第一个 case 标签使用when子句判断Stack是否为空。


import java.util.Stack;import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Stack s when s.empty() -> s.push("first"); case Stack s2 -> s2.push("second"); default -> c; }; }}
复制代码


对应的代码在-> 右侧,只有在 Stack 为空时才会执行。

对于带有模式的 case 标签,顺序很重要


在使用带模式的 case 标签时,开发人员必须确保不会因为顺序产生任何与类型或子类型层次结构相关的问题。这是因为,与常量 case 标签不同,case 标签中的模式使得选择器表达式可以匹配多个包含模式的 case 标签。Switch 模式匹配特性会匹配第一个模式与选择器表达式值相同的标签。


如果一个 case 标签模式的类型是在它之前出现的另一个 case 标签模式的类型的子类型,则会发生编译时错误,因为后一个 case 标签将被识别为不可访问代码。


下面是一个演示程序,你可以编译并运行它,其中类型为Object的 case 标签模式控制了后续类型为Stack的代码标签模式。


import java.util.Stack;
public class SampleClass { static Object get(Object c) { return switch (c) { case Object o -> c; case Stack s -> s.pop(); }; }}
复制代码


在编译这个类时,会产生以下错误信息:


SampleClass.java:12: error: 该case标签为它前面的case标签所控制        case Stack s  -> s.pop();             ^
复制代码


像下面这样对调两个 case 标签的顺序就可以修复这个编译时错误:


public class SampleClass {    static Object get(Object c) {        return switch (c) {            case Stack s  -> s.pop();            case Object o  -> c;        };    }}
复制代码


类似地,如果 case 标签包含的模式与前面出现的无条件/非保护模式 case 标签具有相同的引用类型,则会导致编译类型的错误,就像下面的类这样:


import java.util.Stack;import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Stack s -> s.push("first"); case Stack s2 -> s2.push("second"); }; }}
复制代码


上述代码在编译时会产生以下错误:


SampleClass.java:13: error: 该case标签为它前面的case标签所控制        case Stack s2 -> s2.push("second");             ^
复制代码


为了避免这种错误,case 标签的顺序应该直观、可读。应该首先列出常量标签,然后是case null标签、受保护的模式标签和非受保护类型的模式标签。default case 标签可以与case null 标签合并,也可以单独作为最后一个 case 标签。下面的类演示了正确的排序:


import java.util.Collection;import java.util.Stack;import java.util.Vector;
public class SampleClass { static Object get(Collection c) { return switch (c) { case null -> c; //case label null case Stack s when s.empty() -> s.push("first"); // 受保护case标签 case Vector v when v.size() > 2 -> v.lastElement(); // 受保护case标签 case Stack s -> s.push("first"); // 非受保护case标签 case Vector v -> v.firstElement(); // 非受保护case标签 default -> c; }; }}
复制代码

模式匹配可用于传统的 switch 语句和穿透语义


模式匹配特性与它是 switch 语句还是 switch 表达式无关。模式匹配也与使用穿透语义的case…:标签还是使用非穿透语义的case…->标签无关。在下面的示例中,模式匹配与 switch 语句而不是与 switch 表达式一起使用。case 标签使用了具有穿透语义的case…:。第一个 case 标签中的when子句使用了一个受保护的模式。


import java.util.Stack;import java.util.Collection;
public class SampleClass { static void get(Collection c) { switch (c) { case Stack s when s.empty(): s.push("first"); break; case Stack s : s.push("second"); break; default : break; } }}
复制代码

模式变量的作用域


模式变量是出现在 case 标签模式中的变量。模式变量的作用域仅限于出现在->箭头右侧的块、表达式或 throw 语句。请看下面的演示代码,default 中使用了来自它前面的 case 标签的模式变量。


import java.util.Stack;
public class SampleClass { static Object get(Object c) { return switch (c) { case Stack s -> s.push("first"); default -> s.push("first"); }; }}
复制代码


上述代码会产生以下编译错误:


import java.util.Collection;SampleClass.java:13: error: cannot find symbol        default -> s.push("first");                   ^  symbol:   variable s  location: class SampleClass
复制代码


出现在受保护 case 标签模式中的模式变量,其作用域包括 when 子句,如下所示:


import java.util.Stack;import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Stack s when s.empty() -> s.push("first"); case Stack s -> s.push("second"); default -> c; }; }}
复制代码


由于模式变量的作用域有限,所以相同的模式变量名可以跨多个 case 标签使用。前面的例子说明了这一点,其中模式变量s用在了两个不同的 case 标签中。


当处理具有穿透语义的 case 标签时,模式变量的作用域扩展到了:右侧的一组语句。这就是为什么在上一节中,使用模式匹配和传统的 switch 语句,可以在两个 case 标签中使用相同的模式变量名。但是,具有穿透语义的 case 标签声明模式变量会导致编译时错误。关于这一点,下面的类可以证明:


import java.util.Stack;import java.util.Vector;import java.util.Collection;
public class SampleClass { static void get(Collection c) { switch (c) { case Stack s : s.push("second"); case Vector v : v.lastElement(); default : System.out.println("default"); } }}
复制代码


第一个语句组中缺少break; 语句,如果第二个语句组中的模式变量v未初始化,则 switch 可能会在第二个语句组处失败。上述类会产生如下编译时错误:


SampleClass.java:12: error: 非法穿透到模式        case Vector v  : v.lastElement();             ^
复制代码


只需在第一个语句组中添加break; 语句就可以修复这个错误:


import java.util.Stack;import java.util.Vector;import java.util.Collection;
public class SampleClass { static void get(Collection c) { switch (c) { case Stack s : s.push("second"); break; case Vector v : v.lastElement(); default : System.out.println("default"); } }}
复制代码

每个 case 标签只能有一个模式


无论是类型为case…:的 case 标签,还是类型为case…->的 case 标签,都不允许在单个 case 标签中组合使用多个模式,否则会导致编译时错误。也许不太明显,在单个 case 标签中组合使用多个模式会导致非法穿透,如下所示:


import java.util.Stack;import java.util.Vector;import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Stack s, Vector v -> c; default -> c; }; }}
复制代码


上述代码会产生以下编译时错误:


SampleClass.java:11: error: 非法穿透到模式        case Stack s, Vector v -> c;                      ^
复制代码

一个 switch 块中只能有一个匹配所有的 case 标签


无论是 switch 语句还是 switch 表达式,在一个 switch 块中包含多个匹配所有的 case 标签都会导致编译时错误。匹配所有的 case 标签是指:


  1. 一个带有模式、可以无条件匹配选择器表达式的 case 标签

  2. default case 标签请看下面的演示类:


import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Collection coll -> c; default -> c; }; }}
复制代码


编译这个类会产生以下错误信息:


SampleClass.java:13: error: switch同时具有无条件模式和default标签        default -> c;        ^
复制代码

类型覆盖的穷尽性


穷尽性意味着 switch 块必须处理选择器表达式所有可能的值。穷尽性要求只有在下列一项或多项适用的情况下才能满足:


a) 使用模式 switch 表达式/语句;


b) 使用case null


c) 选择器表达式不属于以下遗留类型:charbyteshortintCharacterByteShortIntegerString或枚举类型。


为了实现穷尽性,如果子类型不多的话,则可以为选择器表达式类型的每个子类型添加 case 标签。然而,如果子类型众多,这种方法可能会很啰嗦;例如,为Object类型的选择器表达式的每个引用类型添加 case 标签,甚或为Collection类型的选择器表达式的每个子类型添加 case 标签,都是不可行的。


为了演示穷尽性要求,请看下面这个类:


import java.util.Collection;import java.util.Stack;import java.util.LinkedList;import java.util.Vector;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Stack s -> s.push("first"); case null -> throw new NullPointerException("null"); case LinkedList l -> l.getFirst(); case Vector v -> v.lastElement(); }; }}
复制代码


该类会产生以下编译时错误消息:


SampleClass.java:10: error: switch表达式未涵盖所有可能的输入值                return switch (c) {                       ^
复制代码


如下所示,只需要增加一个 default case 标签就可以解决这个问题:


import java.util.Collection;import java.util.Stack;import java.util.LinkedList;import java.util.Vector;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Stack s -> s.push("first"); case null -> throw new NullPointerException("null"); case LinkedList l -> l.getFirst(); case Vector v -> v.lastElement(); default -> c; }; }}
复制代码


像下面这样,如果匹配所有的 case 标签所带有的模式可以无条件匹配选择器表达式,那么就可以满足穷尽性要求,但它无法显式地处理任何子类型。


import java.util.Collection;
public class SampleClass { static Object get(Collection c) { return switch (c) { case Collection coll -> c; }; }}
复制代码


default case 标签可用于满足穷尽性,但如果选择器表达式可能的取值非常少,有时候可以避免使用它。例如,如果选择器表达式的类型为java.util.Vector,只需提供一个子类java.util.Stack的 case 标签模式就可以避免。类似地,如果选择器表达式是密封类类型,则只有在密封类类型的permits子句中声明的类需要由 switch 块处理。

Switch case 标签中的泛型记录模式


Java 20 增加了对 switch 语句/表达式中泛型记录模式类型参数推断的支持。作为一个例子,考虑以下泛型记录:


record Triangle<S,T,V>(S firstCoordinate, T secondCoordinate,V thirdCoordinate){};
复制代码


在下面的 switch 块中,推断出的 record 模式如下:


Triangle<Coordinate,Coordinate,Coordinate>(var f, var s, var t): static void getPt(Triangle<Coordinate, Coordinate, Coordinate> tr){        switch (tr) {           case Triangle(var f, var s, var t) -> …;           case default -> …;        }}
复制代码

使用 MatchException 进行错误处理


Java 19 引入了java.lang.Runtime类的一个新的子类,旨在用更统一的方式处理模式匹配期间的异常。这个名为java.lang.MatchException的新类是一个预览 API。MatchException 不是专门为 switch 中的模式匹配而设计的,而是为所有模式匹配语言结构而设计的。当模式匹配最终未能匹配提供的任何模式时,在运行时可能就会抛出 MatchException。关于这一点,请看下面的应用程序。该应用程序的 case 标签中有一个 record 模式,而它所要匹配的 record 声明了一个除数为 0 的访问器方法。


record DivisionByZero(int i) {    public int i() {        return i / 0;    }}


public class SampleClass {
static DivisionByZero get(DivisionByZero r) { return switch(r) { case DivisionByZero(var i) -> r; };
}
public static void main(String[] argv) {
get(new DivisionByZero(42)); }}
复制代码


示例应用程序编译通过,没有错误,但运行时会抛出MatchException异常:


Exception in thread "main" java.lang.MatchException: java.lang.ArithmeticException: / by zero        at SampleClass.get(SampleClass.java:7)        at SampleClass.main(SampleClass.java:14)Caused by: java.lang.ArithmeticException: / by zero        at DivisionByZero.i(SampleClass.java:1)        at SampleClass.get(SampleClass.java:1)        ... 1 more
复制代码

小结


本文介绍了 Java 新增的对 switch 控制流结构模式匹配的支持。其主要改进是 switch 的选择器表达式可以是任何引用类型,并且 switch 的 case 标签可以包含模式,包括条件模式匹配。而且,如果你不愿意更新整个代码库,那么模式匹配也支持使用传统的 switch 语句及其穿透语义。


原文链接:

https://www.infoq.com/articles/pattern-matching-for-switch/

2023-07-18 08:004960

评论

发布
暂无评论
发现更多内容

2023语言与智能技术竞赛开辟“双赛道”:寻找“全民测评官”,探索AI多模态能力

飞桨PaddlePaddle

Seata 的可观测实践

阿里巴巴云原生

阿里云 云原生 seata

OpenHarmony社区运营报告(2023年4月)

OpenHarmony开发者

OpenHarmony

火山引擎DataTester:小改动带来大收益,A/B实验助力幸福里APP精准优化

字节跳动数据平台

ab测试 A/B 测试

敏捷开发:新一代软件开发模式的优越性与挑战

xfgg

Java 架构 开发效率

为什么MySQL单表不能超过2000万行?

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 5 月 PK 榜

看完这篇,DWS故障修复不再愁

华为云开发者联盟

数据库 后端 华为云 华为云开发者联盟 企业号 5 月 PK 榜

用写代码的方式画图-试下PlantUML吧 | 京东云技术团队

京东科技开发者

开发工具 PlantUML 画图软件 企业号 5 月 PK 榜

面试官:你能和我说一下 CMS 垃圾回收器吗?

Java你猿哥

算法 CMS JVM 垃圾回收器 垃圾收集器

线上问题处理案例:出乎意料的数据库连接池 | 京东云技术团队

京东科技开发者

数据库 GC 线上问题 数据库连接池 企业号 5 月 PK 榜

如何使用、部署 Auto-GPT?系统开发技术分析

Congge420

系统开发 区块链、 autogpt

2023新版Java面试题1300问,刷完直接拿offer!

采菊东篱下

java面试

真香!阿里最新产出分布式进阶实战手册,涵盖分布式架构所有操作

Java你猿哥

架构 微服务架构 Spring Cloud Spring Boot ssm

2023数字中国建设峰会:百度点石获开放群岛开源社区优秀共建单位

百度安全

2023牛客网最全互联网大厂Java面试八股文上线

架构师之道

Java 面试

BSC智能链游戏链系统开发解析

Congge420

区块链追溯系统开发 元宇宙 元宇宙系统开发

关于PCBA元器件布局的重要性

华秋PCB

工具 元器件 PCB 布局 PCB设计

抠图党福音:教你一键分割图像

华为云开发者联盟

华为云 华为云开发者联盟 企业号 5 月 PK 榜 人工资高hi嗯呢该 分割图像

软件测试/测试开发丨Python基本数据类型之字符串

测试人

Python 软件测试 自动化测试 测试开发

深度学习基础入门篇[9.1]:卷积之标准卷积:卷积核/特征图/卷积计算、填充、感受视野、多通道输入输出、卷积优势和应用案例讲解

汀丶人工智能

人工智能 神经网络 深度学习 卷积网络 卷积相关算子

【程序员日记】——从业务编排到低代码 | 京东云技术团队

京东科技开发者

低代码 业务 企业号 5 月 PK 榜 业务编排

TF游戏Ai智能系统开发

Congge420

系统开发 区块链、 智能运维AIOps

软件测试/测试开发丨Python控制流–分支判断和循环

测试人

Python 软件测试 自动化测试 测试开发

硬核!互联网资深大佬手码高并发编程速成笔记(2023版)限时开源

做梦都在改BUG

Java 并发编程 高并发

非常实验——在SSH下通过终端浏览网页

吴脑的键客

浏览器 终端工具

rt下降40%?程序并行优化六步法 | 京东云技术团队

京东科技开发者

性能优化 异步编程 企业号 5 月 PK 榜 多线程优化 并发框架

深度学习基础入门篇[9.2]:卷积之1*1 卷积(残差网络)、2D/3D卷积、转置卷积数学推导、应用实例

汀丶人工智能

人工智能 神经网络 深度学习 卷积网络 卷积核

【实践篇】领域驱动设计:DDD工程参考架构 | 京东云技术团队

京东科技开发者

领域驱动设计 DDD 企业号 5 月 PK 榜 工程架构

LED显示屏如何做到节能

Dylan

效率 能源 节能 LED显示屏

为什么我们拥有庞大的语言模型,而Vision Transformers的规模却很小?

Baihai IDP

人工智能 深度学习 计算机视觉 白海科技 Vision Transformers

聊聊 万亿流量场景下的负载均衡实践

Java你猿哥

负载均衡 ssm 高并发 DNS 负载均衡架构

Java新特性完整指南:Switch模式匹配_编程语言_Deepak Vohra_InfoQ精选文章