代码检查规则语言CodeNavi中代码语句的节点和节点属性

本文分享至华为云社区《CodeNavi 中代码语句的节点和节点属性》。作者:Uncle_Tom


1. 前期回顾

  • 《寻找适合编写静态分析规则的语言》
    根据代码检查中的一些痛点,提出了希望寻找一种适合编写静态分析规则的语言。

    • 可以满足用户对代码检查不断增加的各种需求;
    • 使用户能够通过增加或减少对检查约束条件的控制,实现快速调整检查中出现的误报和漏报;
    • 这种检查语言能够有较低的使用门槛,使用户更专注于检查业务,而不需要关注工具是如何实现的。

    我们称这种检查规则语言为:CodeNavi。文中给出了这种检查规则语言的两个应用场景,以此来说明这种检查规则语言如何满足用户在编写静态检查规则时的期望。

  • 《CodeNavi 规则的语法结构》
    介绍 CodeNavi 检查规则语言在编写规则的基本语法格式。CodeNavi 检查规则语言,通过对代码节点和节点属性的逻辑条件的组合来完成检查的约束条件,从而完成代码检查中需要满足的缺陷模式适配,找到满足要求的代码点。

  • 《CodeNavi 规则的基础节点和节点属性》
    介绍 CodeNavi 检查规则语言在编写时需要使用基础节点和节点属性,这些基础节点包括:节点类型、字面量、一般变量、枚举、成员变量(字段),以及数组。

  • 《CodeNavi 中代码表达式的节点和节点属性》
    介绍 CodeNavi 检查规则语言如何描述代码中的表达式。这些节点主要包括:对象创建表达式、强制类型转换、类型判断表达式、一元表达式、二元表达式、条件表达式/三目运算、方法引用表达式、lambda表达式,以及匿名内部类表达式。

  • 本篇将继续介绍 CodeNavi 中代码里语句和代码块的节点和节点属性。

    • 语句节点包括:赋值语句,
    • 控制流语句包括:跳转语句、条件控制、Switch控制、循环控制、异常处理、静态语句、同步代码块。

2. CodeNavi 中的节点和节点属性

程序是由空格分隔的字符串组成的序列。在程序分析中,这一个个的字符串被称为"token",是源代码中的最小语法单位,是构成编程语言语法的基本元素。

Token可以分为多种类型,常见的有关键字(如if、while)、标识符(变量名、函数名)、字面量(如数字、字符串)、运算符(如+、-、*、/)、分隔符(如逗号,、分号;)等。

我们只需要给代码的不同节点给出一个定义,然后通过条件语句来描述对这些节点的要求,使之符合缺陷检查的模式,就可以完成检查规则的定义。

2.1. 规则节点和节点属性图例

程序是由空格分隔的字符串组成的序列。在程序分析中,这一个个的字符串被称为"token",是源代码中的最小语法单位,是构成编程语言语法的基本元素。

Token可以分为多种类型,常见的有关键字(如if、while)、标识符(变量名、函数名)、字面量(如数字、字符串)、运算符(如+、-、*、/)、分隔符(如逗号,、分号;)等。

我们只需要给代码的不同节点给出一个定义,然后通过条件语句来描述对这些节点的要求,使之符合缺陷检查的模式,就可以完成检查规则的定义。

2.1.1. 节点

  • 图例

  • 节点和子节点都使用个图例

  • 规则语言中使用节点的 “英文名”,这样便于规则的编写。

2.2. 节点集

  • 图例:

  • 节点的集合。

2.3. 属性

  • 图例

  • 规则语言中使用属性的 “英文名”,这样便于规则的编写。

3. 语句

程序语言中包含多种语句,每种语句都有其特定的作用。

  • 样例代码
// 表达式语句
// 用于执行表达式,如赋值、方法调用等。

int a = 10; // 赋值表达式
System.out.println("Hello, CodeNavi!"); // 方法调用表达式

// 条件语句
// 用于基于条件执行不同的代码分支。

// if 语句
int score = 75;
if (score > 70) {
    System.out.println("Pass");
}

// if-else 语句
if (score > 70) {
    System.out.println("Pass");
} else {
    System.out.println("Fail");
}

// switch 语句
int month = 4;
switch (month) {
    case 1: System.out.println("January"); break;
    case 2: System.out.println("February"); break;
    // ...
    default: System.out.println("Invalid month");
}

// 循环语句
// 用于重复执行一段代码。

// for 循环
for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

// while 循环
int i = 0;
while (i < 10) {
    System.out.println(i++);
}

// do-while 循环
int i = 0;
do {
    System.out.println(i++);
} while (i < 10);

// 跳转语句
// 用于控制程序流程,如跳过循环的迭代或退出循环。

// break 语句
for (int i = 0; i < 10; i++) {
    if (i == 5) break;
    System.out.println(i);
}

// continue 语句
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) continue; // 跳过偶数
    System.out.println(i);
}

// 异常处理语句
// 用于处理程序运行时可能出现的异常。

// try-catch 语句
try {
    int result = 10 / divisor;
} catch (ArithmeticException e) {
    System.out.println("Cannot divide by zero");
}

// try-catch-finally 语句
try {
    // 可能抛出异常的代码
} catch (Exception e) {
    // 异常处理
} finally {
    // 无论是否发生异常都会执行的代码
}

// 返回语句
// 用于从方法返回一个值或退出方法。

public int max(int a, int b) {
    return (a > b) ? a : b;
}

3.1. 赋值语句(assignStatement)

赋值语句是编程中最基本的操作之一,几乎所有的编程语言都支持赋值操作。

赋值语句用于将一个值或表达式的结果存储到一个变量中。赋值语句的基本形式是将一个表达式的结果赋给一个变量名。

其作用主要包括:

  • 初始化变量
    在程序开始时,使用赋值语句给变量赋予初始值。

  • 存储数据
    将计算结果或常量值存储到一个变量中,以便在程序的后续部分使用。

  • 更新变量值
    在程序执行过程中,可能需要更新变量的值以反映程序状态的变化。

  • 简化代码
    通过将复杂表达式的结果赋值给变量,可以简化代码,提高可读性。

  • 样例代码

int a = 10;

String b = "string" + a;
  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
lhs左值valueAccess类节点a = 10;assignStatement ass where ass.lhs.name == “a”;
rhs右值literal类节点、valueAccess类节点、functionCall类节点a = 10;assignStatement ass where ass.rhs.value == 10;

4. 控制流语句

控制流语句是编程语言中用于控制程序执行流程的语句,它们决定了程序中代码的执行顺序。

  • 代码块分组
    使用大括号 {} 可以将多条语句组织在一起作为一个整体来执行。

  • 条件执行
    允许程序根据条件判断来选择不同的执行路径。例如,if 语句可以根据条件为真或假来执行不同的代码块。

  • 多路径选择
    使用 switch 语句可以根据变量值选择多个执行路径之一。

  • 循环执行
    允许程序重复执行一段代码直到满足特定条件。例如,for 和 while 循环可以在满足循环条件时不断迭代。

  • 异常处理
    使用 try、catch 和 finally 块可以捕获和处理程序运行时发生的异常。

  • 跳转语句
    程序中的跳转语句允许改变程序的执行流程,使得程序可以跳过某些代码块或直接跳到程序的其他部分执行。包括:break、continue、return、throw。

4.1. 跳转语句

程序中的跳转语句允许改变程序的执行流程,使得程序可以跳过某些代码块或直接跳到程序的其他部分执行。

跳转语句:

  • break 语句:立即终止最近的 for 或 while 循环。
  • continue 语句:跳过当前循环的剩余部分,开始下一次迭代。
  • return 语句:从当前函数返回,并可以携带一个值。
  • throw 语句:用于抛出一个异常,可以是预定义的异常类型或用户自定义的异常类型。

4.1.1. continue语句(continueStatement)

continue 语句用于跳过当前循环的剩余部分,并开始执行下一次循环的迭代。这通常用于在满足某个特定条件时不想执行循环体中剩余的代码块。

以下是一些使用 continue 语句的场景:

  • 跳过不符合条件的元素
    处理一个集合,比如数组或列表,并且只想对满足特定条件的元素执行操作时,可以使用 continue 来跳过不满足条件的元素。

  • 避免重复处理
    如果循环中检测到某个元素已经被处理过,可以使用 continue 跳过对它的进一步处理。

  • 减少嵌套循环的复杂性
    在嵌套循环中,如果外层循环的某个条件满足,可能就不需要执行内层循环的任何迭代,这时可以使用 continue 来跳过内层循环。

  • 样例代码
for (int i = 0; i < 10; i++) {
    // 跳过偶数
    if (i % 2 == 0) {
        continue;
    }
    // 只打印奇数
    System.out.println(i);
}

  • 图例

4.1.2. break语句(breakStatement)

break 语句的作用是立即终止最内层的 for、while 或其他循环结构的执行。当执行到 break 语句时,程序会跳出当前的循环体,继续执行循环之后的代码。

break 语句的一些主要作用:

  • 提前退出循环
    当满足特定条件时,你可能希望立即退出循环,而不是等待循环自然结束。

  • 避免无限循环
    在某些情况下,循环的条件可能依赖于循环体内部的某些操作结果,使用 break 可以避免无限循环。

  • 搜索和查找
    在搜索或查找任务中,一旦找到所需的元素或满足特定条件,使用 break 可以立即退出循环。

  • 错误处理
    在循环中进行某些操作时,如果发生错误或异常情况,可以使用 break 来退出循环。

  • 控制复杂循环逻辑
    在嵌套循环中,break 可以用来从外层循环中退出,而不仅仅是内层循环。

  • 样例代码

// break 语句
for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;
    }
    System.out.println(i);
}
  • 图例

4.1.3. return语句(returnStatement)

return 语句的作用是从一个函数或子程序中返回一个值,并终止该函数的执行。

return 语句是函数实现其目的的关键,它允许函数将结果传递给调用者,并在必要时提前退出函数的执行。

以下是 return 语句的一些关键作用:

  • 返回结果
    函数通常用于执行某些计算或操作,并返回结果。使用 return 语句可以将这些结果传递回调用函数的地方。

  • 提前退出函数
    如果函数在执行过程中遇到某些条件,可能需要立即退出并返回一个值(或不返回任何值)。

  • 控制函数的流程
    在复杂的函数中,return 可以用于控制程序的执行流程,例如从嵌套的逻辑结构中返回。

  • 错误处理
    在函数中检测到错误或异常情况时,可以使用 return 语句返回错误代码或错误信息。

  • 简化代码
    通过使用 return,可以在满足特定条件时简化代码逻辑,避免使用多个 if 语句或条件判断。

  • 样例代码

// 返回语句
// 用于从方法返回一个值或退出方法。

public int max(int a, int b) {
    return (a > b) ? a : b;
}
  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
returnValue返回值任意节点return a;returnStatement rs where rs.returnValue.name == “a”;

4.1.4. 异常抛出语句(throwStatement)

使用 throw 语句抛出异常是异常处理机制的一部分,它允许开发者明确地指出程序中可能出现的错误,并提供一种机制来处理这些错误。
throw 语句用于在代码的特定位置手动抛出一个异常。这个异常可以是预定义的异常类型,也可以是用户自定义的异常类型。

throw 语句的一些主要作用:

  • 异常处理
    当程序检测到一个错误或异常情况时,可以使用 throw 抛出一个异常,从而中断正常的程序流程。

  • 错误传播
    在方法中抛出的异常可以被方法的调用者捕获和处理,或者继续向上传播,直到被捕获或导致程序终止。

  • 强制方法实现
    在的接口或抽象类中,可以使用 throw 语句来强制实现某些方法,尽管这些方法没有具体的实现代码。

  • 方法签名中的异常声明
    当一个方法声明它可能会抛出特定的异常时,这些异常需要在方法的签名中声明。如果这些异常是必须被调用者处理的,可以使用 throw 语句来抛出。

  • 样例代码

throw new Exception("Get exception!");
  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
operand抛出异常nodethrow new Exception();throwStatement tr where
  tr.operand is objectCreationExpression;

4.2. 条件控制(ifBlock)

条件控制语句的作用是允许程序根据不同的条件来决定执行哪些代码块。

以下是条件控制语句的主要作用:

  • 决策制定
    条件控制语句允许程序基于特定的条件(通常是变量或表达式的值)来做出决策。

  • 功能开关
    在开发过程中,条件控制语句可以用于临时启用或禁用某些功能。

  • 状态管理
    在需要根据程序的状态来执行不同操作时,条件控制语句可以检查状态并做出相应的响应。

  • 避免错误
    通过检查条件,可以避免执行可能导致错误的代码,例如除以零或访问未初始化的变量。

  • 逻辑选择
    条件控制语句允许程序在多个选项中选择一个执行,例如使用 if 语句来选择两个不同的操作之一。

  • 代码分支
    它们可以创建代码的分支路径,使得程序可以根据不同的条件执行不同的代码段。

  • 增强程序的灵活性
    允许程序根据不同的输入或状态来动态调整其行为。

  • 实现复杂的逻辑
    多个条件控制语句可以嵌套使用,以实现更复杂的逻辑判断。

  • 控制循环的执行
    在循环中使用条件控制语句可以决定何时开始或结束循环的迭代。

  • 资源管理
    条件控制语句可以用于在满足特定条件时分配或释放资源。

  • 错误处理
    它们可以用于检测错误条件,并执行错误处理代码,比如记录日志或向用户报告错误。

  • 样例代码

if(num > 10) { // if block
    // then block
    System.out.println("m > 10");
} else {
   // else block     
   System.out.println("m <= 10");
}

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
conditionif条件binaryOperation节点if (m > 10) {
  System.out.println(“m > 10”);
} else {
  System.out.println(“m <= 10”);
}
ifBlock ib where
  ib.condition contain binaryOperation bo where
    bo.operator == “>”;
thenBlockif条件为true执行的语句block语句块if (m > 10) {
  System.out.println(“m > 10”);
} else {
  System.out.println(“m <= 10”);
}
ifBlock ib where
  ib.thenBlock contain stringLiteral ss where
    ss.value == “m > 10”;
elseBlockif条件为false执行的语句block语句块if (m > 10) {
  System.out.println(“m > 10”);
} else {
  System.out.println(“m <= 10”);
}
ifBlock ib where
  ib.elseBlock contain stringLiteral ss where
    ss.value == “m <= 10”;

4.3. Switch控制

switch 语句是一种选择控制流语句,它允许程序根据不同的条件执行不同的代码块。switch 语句的主要作用是提供一个替代多个 if…else if…else 语句的方法,使得代码更加清晰和易于管理。

以下是 switch 语句的一些关键特点和作用:

  • 多条件选择
    switch 语句允许你根据不同的变量值或表达式结果来选择执行不同的代码块。

  • 默认行为
    switch 语句通常包含一个 default 子句,用于处理没有匹配到任何 case 的情况,类似于 if…else if…else 语句中的 else 部分。

  • 减少嵌套
    相比使用多个 if…else if…else 语句,switch 语句可以减少代码的嵌套层次,使代码结构更清晰。

  • 可中断性
    在 switch 语句中,可以使用 break 语句来中断当前 case 的执行,防止代码继续执行到下一个 case。

  • 提高可读性
    switch 语句通过明确的 case 标签,使得代码的意图更加明显,便于阅读和理解。

  • 易于维护
    当需要添加或修改条件分支时,switch 语句提供了一种更直观的方式,有助于维护和扩展代码。

  • 样例代码

switch (m) {
    case 12:
        System.out.println("hello");
        break;
    case 10:
    case 15:
        System.out.println("CodeNavi");
        break;        
    default:
        System.out.println("default value");
}

4.3.1. switch语句块(switchBlock)

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
selectorswitch语句的判断条件任意节点switch (m) {}switchBlock swb where
  swb.selector.name == “m”;

4.3.2. case语句块(caseStatement)

  • 图例

  • 规则样例

caseStatement cs where cs contain literal;

4.3.3. default语句块(defaultStatement)

  • 图例

  • 规则样例

switchBlock swb where swb contain defaultStatement;

4.4. 循环控制

循环控制语句是程序设计中非常基础且强大的工具,它们使得程序能够以一种高效和灵活的方式处理重复性任务。常见的循环控制语句包括 for 循环、while 循环和 do…while 循环等。

以下是循环控制语句的一些关键特点和作用:

  • 重复执行
    循环控制语句允许代码块在满足循环条件时重复执行,这使得处理大量数据或执行重复任务变得简单高效。

  • 条件控制
    循环控制语句通常与条件语句结合使用,根据条件的变化来决定是否继续执行循环或退出循环。

  • 迭代操作
    循环控制语句常用于迭代数据结构(如数组、列表、集合等)中的元素,执行对每个元素的操作。

  • 控制执行流程
    循环控制语句中的 break 和 continue 可以用来改变循环的执行流程。break 用于立即退出循环,而 continue 用于跳过当前迭代,直接进入下一次循环。

  • 实现算法逻辑
    许多算法和数据处理任务需要循环结构来实现,例如排序、搜索、遍历等。

  • 资源管理
    在处理文件、网络连接等资源时,循环可以用来重复读取或写入数据,直到达到预期的条件。

  • 模拟时间延迟
    在某些情况下,循环可以用来模拟时间延迟,例如通过循环等待某个事件发生。

  • 减少代码冗余
    通过循环,可以避免编写重复的代码块,使得程序更加简洁和易于维护。

4.4.1. 循环语句块(loopBlock)

包括:forBlock, forEachBlock, doWhileBlock, whileBlock

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
condition循环条件任意节点while(i > list.size()) {
  i++;
}
whileBlock wb where
  wb.condition contain binaryOperation bo where
    bo.lhs.name == “i”;
body循环体body语句块while(i > list.size()) {
  i++;
}
whileBlock wb where
  wb.body contain unaryOperation;
body.statementNumbody语句块的语句数量数值while(i > list.size()) {
  i++;
  System.out.print(“xxx”);
}
whileBlock wb where
  wb.body.statementNum == 2;
firstStatementloopBlock的第一条语句任意节点while(i > list.size()) {
  i++;
  System.out.print(“xxx”);
}
whileBlock wb where
  wb.firstStatement contain unaryOperation;
lastStatementloopBlock的最后一条语句任意节点while(i > list.size()) {
  i++;
  System.out.print(“xxx”);
}
whileBlock wb where
  wb.lastStatement contain functionCall;

4.4.2. for循环代码块(forBlock)

  • 样例代码
for (int i = 0; i < list.size(); i++) {
    i++;
}

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
initialization变量初始化variableDeclaration、 variableAccess节点for (int i = 0; i < list.size(); i++) {}forBlock fb where
  fb.initialization.name == “i”;
condition循环条件binaryOperationfor (int i = 0; i < list.size(); i++) {}forBlock fb where
  fb.condition.rhs is functionCall;
iteration迭代操作unaryOperation节点for (int i = 0; i < list.size(); i++) {}forBlock fb where
  fb.iteration.operator == “++”;
body循环体body语句块for (int i = 0; i < list.size(); i++) {
  i++;
}
forBlock fb where
  fb.body contain variableAccess vs where
    vs.name == “i”;
body.statementNumbody语句块的语句数量数值for (int i = 0; i < list.size(); i++) {
  i++;
}
forBlock fb where
  fb.body.statementNum == 1;
firstStatementforBlock的第一条语句任意节点for (int i = 0; i < list.size(); i++) {
  i++;
}
forBlock fb where
  fb.firstStatement contain unaryOperation;
lastStatementforBlock的最后一条语句任意节点for (int j1 = 1; j1 < 50 && k1 < 50; j1++, k1++) {
  System.out.println(j1)
  k1++;
}
forBlock fb where
  fb.lastStatement contain unaryOperation;

4.4.3. forEach循环代码块(forEachBlock)

  • 样例代码
List<String> list = Arrays.asList("1","2","3");

for (String str : list) {
    System.out.println(str)
}

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
variable循环变量variableDeclaration节点for (String str : list) {
  System.out.println(str);
}
forEachBlock fb where and(
  fb.variable is variableDeclaration,
  fb.variable.name == “str”
);
iterable被循环的变量任意节点for (String str : list) {
  System.out.println(str);
}
forEachBlock fb where
  fb.iterable.name == “list”;
body循环体body语句块for (String str : list) {
  System.out.println(str);
}
forEachBlock fb where
  fb.body contain functionCall;
body.statementNumbody语句块的语句数量数值for (String str : list) {
  System.out.println(str);
}
forEachBlock fb where
  fb.body.statementNum == 1;
firstStatementforEachBlock的第一条语句任意节点for (String str : list) {
  System.out.println(str);
}
forEachBlock fb where
  fb.body contain functionCall;
lastStatementforEachBlock的最后一条语句任意节点for (String str : list) {
  System.out.println(str + “1”);
  System.out.println(str + “2”);
}
forEachBlock fb where
  fb.lastStatement contain functionCall;

4.4.4. while循环语句块(whileBlock)

  • 样例代码
int i = 0;
while(i < 10) {
    i = i + 1;
}

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
condition循环条件任意节点while(i > list.size()) {
  i++;
}
whileBlock wb where
  wb.condition contain binaryOperation bo where
    bo.lhs.name == “i”;
body循环体body语句块while(i > list.size()) { i++;}whileBlock wb where wb.body contain unaryOperation;
body.statementNumbody语句块的语句数量数值while(i > list.size()) {
  i++;
  System.out.print(i);
}
whileBlock wb where
  wb.body.statementNum == 2;
firstStatementwhileBlock的第一条语句任意节点while(i > list.size()) {
  i++;
  System.out.print(i);
}
whileBlock wb where
  wb.firstStatement contain unaryOperation;
lastStatementwhileBlock的最后一条语句任意节点while(i > list.size()) {
  i++;
  System.out.print(i);
}
whileBlock wb where
  wb.lastStatement contain functionCall;

4.4.5. do-while语句块(doWhileBlock)

  • 样例代码
int i = 0;
do { 
    i++;
    System.out.print(i);
} while (i < 10);
  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
condition循环条件任意节点do {
  i++;
} while (i < 10);
doWhileBlock wb where
  wb.condition contain binaryOperation bo where
    bo.lhs.name == “i”;
body循环体body语句块do {
  i++;
} while (i < 10);
doWhileBlock wb where
  wb.body contain unaryOperation;
body.statementNumbody语句块的语句数量数值do {
  i++;
  System.out.print(i);
} while (i < 10);
whileBlock wb where
  wb.body.statementNum == 2;
firstStatementforBlock的第一条语句任意节点do {
  i++;
  System.out.print(i);
} while (i < 10);
doWhileBlock wb where
  wb.firstStatement contain unaryOperation;
lastStatementforBlock的最后一条语句任意节点do {
  i++;
  System.out.print(i);
} while (i < 10);
doWhileBlock wb where
  wb.lastStatement contain functionCall;

4.5. 异常处理

程序中的异常处理是一种错误检测和响应机制,它有助于编写更加健壮、可靠和易于维护的软件。

它的作用包括但不限于以下几点:

  • 错误检测
    异常处理允许程序在运行时检测到错误或异常情况,并采取相应的措施。

  • 防止程序崩溃
    通过捕获和处理异常,程序可以在遇到错误时继续运行,而不是直接崩溃或终止。

  • 支持自定义异常
    开发者可以定义自己的异常类型,以更精确地表达特定错误情况。

  • 资源管理
    异常处理确保即使在发生错误的情况下,程序也能够正确地释放或管理资源,如文件句柄、网络连接等。

  • 提供错误信息
    异常处理允许程序在发生错误时提供有用的错误信息,帮助开发者或用户诊断问题。

  • 分离错误处理代码
    通过将错误处理逻辑与正常业务逻辑分离,可以使代码更加清晰和易于维护。

  • 支持多级错误处理
    异常处理允许程序在不同级别上捕获和处理错误,例如在函数内部捕获异常,然后在调用者中进一步处理。

  • 控制程序流程
    异常处理提供了一种控制程序流程的方式,允许程序在特定错误发生时跳转到特定的错误处理代码。

  • 维护程序的健壮性
    通过合理地使用异常处理,可以增强程序的健壮性,使其能够优雅地处理各种意外情况。

  • 样例代码

try {
    int num = 1/0;
} catch (Exception e) {
    throw new RuntimeException(e);
} finally {
    System.out.println("finally");
}

4.5.1. 异常捕捉代码块(exceptionBlock)

包括: tryBlock、catchBlock、finallyBlock

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
tryBlocktry语句块tryBlock节点try {
  int num = 1/0;
} catch (Exception e) {
  throw new RuntimeException(e);
} finally {
  System.out.println(“finally”);
}
exceptionBlock eb where
  eb.tryBlock contain variableDeclaration;
catchBlocks所有的catch语句块集catchBlock节点的集合try {
  int num = 1/0;
} catch (Exception e) {
  throw new RuntimeException(e);
} finally {
  System.out.println(“finally”);
}
exceptionBlock eb where
  eb.catchBlocks contain cb where
    cb contain throwStatement;
finallyBlockfinally语句块finallyBlock节点try {
  int num = 1/0;
} catch (Exception e) {
  throw new RuntimeException(e);
} finally {
  System.out.println(“finally”);
}
exceptionBlock eb where
  eb.finallyBlock contain functionCall fc where
    fc.name == “println”;
4.5.3. catch语句块(catchBlock)
  • 节点属性
名称描述值类型示例DSL 规则
parameters参数集node listtry {
  int num = 1/0;
} catch (Exception e) {
  throw new RuntimeException(e);
} finally {
  System.out.println(“finally”);
}
catchBlock cb where
  cb.parameters contain p where
    p.name == “e”;

4.5.4. tryWithResources异常捕捉代码块(tryWithResources)

  • 样例代码
try (Statement stmt = con.createStatement()) {
    System.out.println("try-with-resources block");
} catch (SQLException e1) {
    System.out.println(e1);
} catch (Exception e2) {
    System.out.println(e2);
}

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
tryBlocktry语句块tryBlock节点try (Statement stmt = con.createStatement()) {
  System.out.println(“try-with-resources block”);
} catch (SQLException e1) {
  System.out.println(e1);
} catch (Exception e2) {
  System.out.println(e2);
}
tryWithResources eb where
  eb.tryBlock contain variableDeclaration;
catchBlocks所有的catch语句块catchBlock节点的集合try (Statement stmt = con.createStatement()) {
  System.out.println(“try-with-resources block”);
} catch (SQLException e1) {
  System.out.println(e1);
} catch (Exception e2) {
  System.out.println(e2);
}
tryWithResources eb where
  eb.catchBlocks contain cb where
    cb contain throwStatement;
finallyBlockfinally语句块finallyBlock节点try (Statement stmt = con.createStatement()) {
  System.out.println(“try-with-resources block”);
} catch (SQLException e1) {
  System.out.println(e1);
} catch (Exception e2) {
  System.out.println(e2);
}
tryWithResources eb where
  eb.finallyBlock contain functionCall fc where
    fc.name == “println”;
resources任意节点若干statements节点的集合try (Statement stmt = con.createStatement()) {
  System.out.println(“try-with-resources block”);
} catch (SQLException e1) {
  System.out.println(e1);
} catch (Exception e2) {
  System.out.println(e2);
}
tryWithResources twr where
  twr.resources contain re where
    re contain functionCall fc where
      fc.name == “createStatement”;

4.6. 静态语句块(staticBlock)

静态语句块(也称为静态初始化块)是一种特殊的代码块,它使用关键字 static 标记。

静态语句块在类或接口的主体中定义,并且在任何对象被创建之前,或者任何静态方法被调用之前执行。由于静态语句块的执行时机和作用域,在类的初始化和资源管理方面,扮演着重要的角色。

静态语句块的作用主要包括以下几点:

  • 初始化静态变量
    静态语句块在类加载时执行,可以用来初始化类的静态变量。

  • 静态常量赋值
    静态语句块可以用来给静态常量赋值,虽然通常静态常量直接赋值更为常见。

  • 静态初始化顺序
    静态语句块的执行顺序是在类变量声明之后,构造函数之前,这可以用来控制类的初始化顺序。

  • 延迟初始化
    静态语句块可以用于延迟初始化,即只有在类被实际使用时才进行初始化。

  • 类级别的条件判断
    静态语句块可以包含逻辑判断,根据条件来执行不同的初始化代码。

  • 执行一次性操作
    静态语句块在类第一次被加载到JVM时执行,并且只执行一次。这使得它适合执行那些只需要执行一次的操作。

  • 静态资源分配
    静态语句块可以用来分配静态资源,如加载配置文件、初始化数据库连接等。

  • 静态工厂方法
    静态语句块可以与静态工厂方法结合使用,以提供类的实例化逻辑。

  • 静态代码复用
    在某些情况下,静态语句块可以用于复用静态代码,避免在多个构造函数或方法中重复相同的初始化代码。

  • 样例代码

static {
    int n = 5;
}
  • 图例

  • 规则样例

staticBlock sb where sb contain variableDeclaration;

4.7. 同步代码块(synchronizedBlock)

同步代码块的作用主要是确保多线程环境下的线程安全。

以下是同步代码块的几个关键作用:

  • 确保原子性
    同步代码块确保了代码块内的一系列操作作为一个整体执行,不可被其他线程中断,从而保证了操作的原子性。

  • 防止数据竞争
    当多个线程尝试同时访问和修改共享资源时,同步代码块可以防止出现数据竞争(Race Condition)的问题。

  • 实现线程互斥
    同步机制通过锁定机制实现线程互斥,即在同一时刻只允许一个线程执行同步代码块。

  • 避免死锁
    虽然同步本身可能导致死锁,但正确使用同步代码块可以避免或减少死锁的发生。

  • 提高数据一致性
    通过同步代码块,可以确保对共享数据的所有访问都是有序的,从而维护数据的一致性。

  • 控制并发访问
    同步代码块可以用来控制对特定资源的并发访问,例如,限制同时访问数据库连接的线程数量。

  • 实现线程通信
    同步代码块可以与wait()、notify()和notifyAll()方法一起使用,实现线程间的协调和通信。

  • 保护关键资源
    同步代码块可以用来保护那些不应该被多个线程同时修改的关键资源。

  • 提高程序的可维护性
    通过集中管理对共享资源的访问,同步代码块可以提高程序的可维护性。

  • 实现线程安全的单例模式
    同步代码块常用于实现延迟加载的线程安全的单例模式。

  • 样例代码

// 使用对象锁(任意对象):

synchronized(Object) {
    // 同步代码块
}

// 使用类锁(当前类的Class对象):

synchronized(ClassName.class) {
    // 同步代码块
}

  • 图例

  • 节点属性

名称描述值类型示例DSL 规则
lock任意节点synchronized (i) {
  System.out.println(“hello”);
}
synchronizedBlock sy where
  sy.lock contain variableAccess va where
    va.name == “i”;
body同步块block语句块synchronized (i) {
  System.out.println(“hello”);
}
synchronizedBlock sy where
  sy.body contain functionCall fc where
    fc.name == “println”;
body.statementNumbody语句块的语句数量数值synchronized (i) { System.out.println(“hello”);}synchronizedBlock sb where
  sb.body.statementNum == 1;
firstStatementsynchronizedBlock的第一条语句任意节点synchronized (i) {
  System.out.println(“hello”);
}
synchronizedBlock sb where
  sb.firstStatement contain unaryOperation;
lastStatementsynchronizedBlock的最后一条语句任意节点synchronized (i) {
  System.out.println(“hello”);
}
synchronizedBlock sb where
  sb.lastStatement contain functionCall;

5. CodeNavi插件

  • 在Vscode 的插件中,查询:codenavi,并安装。

  • 使用插件的链接安装: https://marketplace.visualstudio.com/items?itemName=HuaweiCloud.codenavi

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c语言中的字符串函数

strstr函数 函数介绍 strstr 用于在一个字符串中查找另一个字符串的首次出现。 我们来看这个函数的参数名字&#xff1a;haysytack&#xff08;干草堆&#xff09;needle&#xff08;针&#xff09;,这个其实就是外国的一句谚语&#xff1a;在干草堆中找一根针&#xff0c;就…

Type-C PD芯片:引领充电技术的新纪元

随着科技的飞速发展&#xff0c;人们对电子设备的依赖日益加深&#xff0c;对充电速度、效率和安全性的要求也越来越高。在这样的背景下&#xff0c;Type-C PD&#xff08;Power Delivery&#xff09;芯片应运而生&#xff0c;以其高效、安全、智能的特点&#xff0c;成为了充电…

SAP PP学习笔记26 - User Status(用户状态)的实例,订单分割中的重要概念 成本收集器,Confirmation(报工)的概述

上面两章讲了生产订单的创建以及生产订单的相关内容。 SAP PP学习笔记24 - 生产订单&#xff08;制造指图&#xff09;的创建_sap 工程外注-CSDN博客 SAP PP学习笔记25 - 生产订单的状态管理(System Status(系统状态)/User Status(用户状态)),物料的可用性检查&#xff0c;生…

nssm的下载和使用

nssm&#xff08;Non-Sucking Service Manager&#xff09;是一个用于在Windows系统上管理服务的工具。它允许你将.exe文件和.bat文件转换为Windows服务&#xff0c;并提供了一些功能来管理这些服务。 下载和安装 首先&#xff0c;你需要从nssm官方网站&#xff08;https://n…

STM32智能停车场管理系统教程

目录 引言环境准备智能停车场管理系统基础代码实现&#xff1a;实现智能停车场管理系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;停车场管理与优化问题解决方案与优化收尾与总结 1. 引言 智能停车场管…

echarts 实现水利计算模型-雨量,流量,时间分割线

需求背景解决效果ISQQW代码地址index.vue 需求背景 实现水利计算模型-雨量&#xff0c;流量&#xff0c;时间分割线 解决效果 ISQQW代码地址 链接 index.vue <!--/** * author: liuk * date: 2024/06/13 * describe: 洪水预报结果图表 */--> <template><di…

MySQl高级篇-事务、锁机制、MVCC

存储引擎的选择 在选择存储引擎时&#xff0c;应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统&#xff0c;还可以根据实际情况选择多种存储引擎进行组合。 InnoDB&#xff1a;是Mysql的默认存储引擎&#xff0c;支持事务、外键。如果应用对事务的完整性有比较…

MMLab-dataset_analysis

数据分析工具 这里写目录标题 数据分析工具dataset_analysis.py数据可视化分析 benchmark.pybrowse_coco_json.pybrowse_dataset.pyOptimize_anchors mmyolo、mmsegmentation等提供了数据集分析工具 dataset_analysis.py 数据采用coco格式数据 根据配置文件分析全部数据类型或…

【开源】开源数据库工具推荐

Mysql开源工具推荐 dbeaver下载网速太慢了&#xff0c;这么好用的开源工具&#xff0c;可以从镜像站中下载&#xff1a; 下载地址&#xff1a; https://mirrors.nju.edu.cn/github-release/dbeaver/dbeaver/24.1.1/ Redis开源工具推荐 好看好用&#xff0c;UI真是做的很不…

PE文件(九)导出表

引入导出表 Win32下的一个PE文件&#xff0c;是由多个PE文件组成。比如通过OD打开一个Ipmsg.exe&#xff0c;查看模块M&#xff0c;会发现模块有一个ipmsg.exe文件和多个动态链接库.dll文件。 当一个exe文件通过使用动态链接库.dll的方式导出某.dll文件某函数进行使用时&#…

Qt+ESP32+SQLite 智能大棚

环境简介 硬件环境 ESP32、光照传感器、温湿度传感器、继电器、蜂鸣器 基本工作流程 上位机先运行&#xff0c;下位机启动后尝试连接上位机连接成功后定时上报传感器数据到上位机&#xff0c;上位机将信息进行处理展示判断下位机传感器数据&#xff0c;如果超过设置的阈值&a…

Puppeteer动态代理实战:提升数据抓取效率

引言 Puppeteer是由Google Chrome团队开发的一个Node.js库&#xff0c;用于控制Chrome或Chromium浏览器。它提供了高级API&#xff0c;可以进行网页自动化操作&#xff0c;包括导航、屏幕截图、生成PDF、捕获网络活动等。在本文中&#xff0c;我们将重点介绍如何使用Puppeteer…

项目部署笔记

1、安全组需开放&#xff08;如果不开放配置nginx也访问不到&#xff09; 2、域名解析配置IP(子域名也需配置IP&#xff0c;IP地址可以不同) 3、如果出现图片获其他的文件找不到的情况请仔细检查一下路径是否正确 4、服务器nginx配置SSL证书后启动报错&#xff1a; nginx: […

嘉立创EDA隐藏地线或者

https://prodocs.lceda.cn/cn/pcb/side-panel-left-net/#%E9%A3%9E%E7%BA%BF

Ceph集群部署(基于ceph-deploy)

目录 部署Ceph集群的方法 Ceph生产环境推荐 部署Ceph实验&#xff08;基于ceph-deploy&#xff09; 一、准备工作 二、环境准备 1.关闭selinux与防火墙 2.修改主机名并且配置hosts解析映射 3.admin管理节点配置ssh免密登录node节点 4.安装常用软件和依赖包 5.配置时间…

807.力扣每日一题7/14 Java(执行用时分布击败100%)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;算法练习关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 解题思路 解题过程 时间复杂度 空间复杂度 Code 解题思路 首先…

C语言--递归

曾经有一个段子&#xff1a;上大学时&#xff0c;我们的c语言老师说&#xff1a;学c时&#xff0c;如果有50%的同学死在了循环上面&#xff0c;那么就有90%的同学死在了递归上面。接下来&#xff0c;就来看看递归是怎么个事&#xff1f; 一.递归的介绍 递归是指一个函数直接或…

护佑未来!引领儿童安全新时代的AI大模型

引领儿童安全新时代的AI大模型 一. 前言1.1 AI在儿童安全方面的潜在作用1.2 实时监控与预警1.3 个性化安全教育与引导1.4 家长监护与安全意识提升 二. AI大模型的优势2.1. 保护儿童隐私和安全的重要性2.2. AI大模型如何应用于儿童安全领域2.1 儿童内容过滤2.2.1 儿童行为监测 2…

算法力扣刷题记录 四十四【222.完全二叉树的节点个数】

前言 二叉树篇继续。 记录 四十四【222.完全二叉树的节点个数】 一、题目阅读 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都…

Java时间复杂度介绍以及枚举

时间复杂度 从小到大&#xff1a; O(1) 常数阶。复杂度为O(1)与问题规模无关 线性阶 O&#xff08;n&#xff09;比如一个for循环中代码执行n遍 n阶 对数阶 int n9; int i1; while(i<n) { i*2; } 2^x>n时候退出。次数xlog2^n 时间复杂度为O(logN) 根号阶 int…