跳到主要内容

基础语法

语言元素

项目描述
注释使用 ##// 指定,并延伸到行尾,例如 ## 这是一个注释// 这是一个注释 多行注释使用 /*...*/,例如 /* 这是一个多行注释 */
标识符 / 变量必须以 a-zA-Z_$ 开头。之后可以跟随 0-9a-zA-Z_$。例如:有效: var1_a99$1 无效: 9v!a991$ 变量名区分大小写,例如 var1Var1 是不同的变量。注意: 脚本中 不支持带有连字符的变量,例如 commons-logging // 无效的变量名(带连字符) 被视为从变量 commons 中减去 logging,而不是有效变量。脚本中也支持 ant-style 变量,以下是有效的变量名:my.dotted.var 注: 以下关键字是保留的,不能作为变量名或属性使用点操作符:orandeqneltgtlegedivmodnotnulltruefalsenewvardowhilebreakcontinuefunctionreturn。例如:以下是无效的:my.new.dotted.var // 无效('new' 是关键字) 在这种情况下,可以使用带引号的标识符或 [ ] 操作符,例如:my.'new'.dotted.varmy['new'].dotted.var
脚本脚本由零个或多个语句组成,通常包含在一个函数定义块中。脚本可以包括一个或多个 pragma。脚本可以从字符串、文件或 URL 读取。脚本可以创建具有命名参数的函数,这允许后续评估时使用参数。默认情况下,在没有显式 return 语句的情况下,脚本返回最后一个被评估的语句的值。使用 return 关键字,脚本将返回跟随的表达式(或 null)。
#pragma声明一个 pragma,是一种将信息从脚本传达给执行环境的方法。例如 #pragma execution.option 42 将声明一个名为 execution.option 的 pragma,值为 42。Pragma 键可以是标识符或 antish 名称,pragma 值可以是文字(布尔值、整数、实数、字符串、null、NaN)和 antish 名称。尽管 pragma 是语句,但它们在运行时不会被评估;它们是与脚本解析后相关联的常量。用户代码期望从脚本中访问 pragma 映射以更改一些函数行为。有 3 个内置 pragma:jexl.options 使用选项标志语法覆盖评估选项。#pragma jexl.options "+strict -safe +lexical +lexicalShade" 将让脚本以严格模式运行,安全模式为假,词法作用域为真,词法阴影为真。jexl.namespace.*ns_prefix* 声明一个在脚本执行生命周期内有效的命名空间,值为完全限定的命名空间类名。#pragma jexl.namespace.str java.lang.String 将 'str' 声明为使用 String 类的命名空间。jexl.import 与 'new' 操作符配合使用。它声明 new ClassIdentifier(...) 将访问的包 - 按声明顺序 - 以将类名解析为完全限定的类名。#pragma jexl.import java.net 将允许执行 let url = new URL("https://commons.apache.org");,URL 类名被解析为 java.net.URL 完全限定类名。
语句语句可以是空语句、分号(;)、块、条件、变量声明或表达式。语句可以选择性地以分号终止。单个语句或语句块可以被注释。
块是指用大括号({, })包围的多个语句。
局部变量可以使用 letconstvar 关键字定义,其标识规则与上下文变量相同。let 声明一个具有词法块作用域的局部变量(或参数)。该变量只能在其定义块及任何嵌套的子块中访问。这还禁止在该作用域内重新声明变量。注意:这模仿了 Java 行为,与 ECMAScript 不同。const 的行为与 let 类似,但会阻止变量被任何副作用操作符重新分配。var 声明一个作用域为整个脚本的变量,并允许重新定义。基本声明:let x; 带赋值的声明:const theAnswer = 42; 无效声明:var x.y; 局部变量在解析时优先于上下文变量。当脚本使用命名参数创建时,这些参数的行为也像局部变量一样。局部变量不能使用 ant-style 命名,只能使用一个标识符。
表达式表达式可以是文字、变量、赋值、访问操作符、函数定义、函数调用、方法调用或求值操作符。
赋值给变量(my.var = 'a value')赋值。
函数定义在脚本中定义一个函数,通常与局部变量赋值相关联。var fun = function(x, y) { x + y } 还支持以下语法:var fun = (x, y) -> { x + y } var fun = (let x, let y) -> { x + y } const fun = (const x, const y) -> { x + y } function fun(const x, const y) { x + y } 如果函数只有一个参数,则可以省略圆括号 var fun = x -> { x * x }。函数的主体为表达式时,可以省略花括号,如:var fun = x -> x * x。注意,函数可以使用其定义脚本中的局部变量和参数。那些变量的值在定义时绑定到函数环境中。var t = 20; var s = function(x, y) {x + y + t}; t = 54; s(15, 7) 函数闭包在定义时捕获 't';评估结果将导致 15 + 7 + 20 = 42
函数调用调用函数遵循常规约定,例如 fun(17, 25) 将使用参数 1725 调用 fun 函数。
方法调用调用对象的方法,例如 "hello world".hashCode() 将调用 "hello world" 字符串的 hashCode 方法。在多个参数和重载的情况下,JEXL 将尽力找到最合适的、没有歧义的方法调用。
访问操作符允许通过使用方括号或点符号来评估对象的属性、集合的值或数组中的元素,例如 foo.bar 将访问 foo 对象的 bar 属性。arr1[0] 将访问 arr1 数组的第一个元素。安全访问操作符 foo?.bar 会在导航路径上的任何 null 或不存在的引用时快捷处理,从而允许无错误的安全导航。在前面的表达式中,如果 foo 为 null,则整个表达式将评估为 null。这是防御性表达式的有效快捷方式,例如 x?.y?.z,否则将表达为 x? (x.y? (x.y.z ?: null) :null) : null。安全访问数组操作符(如 foo?[bar])提供与安全访问操作符相同的行为,并在导航路径上的任何 null 或不存在的引用时快捷处理,从而允许无错误的安全导航。注意,这也可以链式使用,如 x?[y]?[z]。访问操作符可以在 JexlArithmetic 中被重载,因此操作符的行为会根据操作符参数的类型而有所不同。
求值操作符执行一个、两个或三个参数值的计算、逻辑或比较操作,这些值是表达式,例如 40 + 2 将调用两个整数文字之间的 add 操作符。
@注解它们允许将语句的执行包装在提供的调用者中;典型示例包括:@synchronized(x) x.someMethod(); 注解可以用零个或多个参数声明;@lenient x.someMethod(); @synchronized(x) x.someMethod(); @parallel(pool, 8) x.someMethod(); 也可以链式声明,如:@lenient @silent x.someMethod();

访问

操作符描述
数组访问数组元素可以使用方括号或点符号访问,例如 arr1[0]arr1.0 等效
列表访问列表元素可以使用方括号或点符号访问,例如 list[0]list.0 等效
映射访问映射元素使用方括号访问,例如 map[0]map['name']map[var] 注意 map['7']map[7] 参考不同的元素。具有数字键的映射元素也可以使用点符号访问,例如 map[0]map.0 等效。注意 map.1map.01 参考不同的元素,而 map.1map[01] 等效。
JavaBean 属性访问可以使用方括号或点符号访问定义了适当 getter 方法的 JavaBean 对象的属性,例如 foo['bar']foo.bar 等效。将调用适当的 Foo.getBar() 方法。注意 foo.Barfoo.bar 都可以使用
索引 JavaBean 属性访问可以使用方括号或点符号访问定义了适当 getter 方法的 JavaBean 对象的索引属性,例如 x.attribute['name']x.attribute.name 等效。将调用适当的 Foo.getAttribute(String index) 方法
公共字段访问可以使用方括号或点符号访问 Java 对象的公共字段,例如 foo['bar']foo.bar 等效。
鸭子类型集合属性访问可以使用方括号或点符号访问定义了公共 Object get(String name) 方法的 Java 类的属性,例如 foo['bar']foo.bar 等效。将调用适当的 Foo.get(String index) 方法,参数为 "bar" 字符串

条件语句

语句描述
if经典的 if/else 语句,例如 if ((x * 2) == 5) { y = 1; } else { y = 2; }
for遍历数组、集合、映射、迭代器或枚举的项,例如 for (let item : list) { x = x + item; } 其中 list 是指向任何可迭代结构的上下文变量。也支持使用上下文变量的以下语法:for (item : list) { x = x + item; } 注意循环变量 item 在循环评估后可访问。最后,支持使用局部变量、初始值、循环条件和循环步骤的传统语法。for (let i = 0; i < size(list); ++i) { x = x + list[i]; } 其中 list 是指向类似数组结构的局部变量。 现已不支持使用 foreach(item in list)
while循环直到满足条件,例如 while (x < 10) { x = x + 2; }
do/while循环直到满足条件,例如 do { x = x + 2; } while (x < 10)

控制流

语句描述
if经典的 if/else 语句,例如 if ((x * 2) == 5) { y = 1; } else { y = 2; }
continue在循环(do/while/for)中,终止当前迭代中的语句执行,并跳至下一个循环迭代。let text = ''; for (let i : (4..2)) { if (i === 3) { continue; } text += i; } text; 将评估为 "42"。
break在循环(do/while/for)中,终止当前迭代中的语句执行并退出循环。let i = 33; while (i < 66) { if (i == 42) { break; } i += 1; } i; 将评估为 42。
returnreturn 语句结束执行并指定要返回给脚本或 lambda 调用者的值。function f(x) { if (x == 42) { return "生命、宇宙及一切的答案"; } return x } f(41); 将评估为 41。
throwthrow 语句抛出一个对象。当前脚本的执行将停止(抛出后面的语句不会被执行),控制将传递到调用栈中的第一个 catch 块。如果在调用函数中没有 catch 块,则脚本执行将终止。
try/catch/finallytry...catch 语句由一个 try 块和一个 catch 块、一个 finally 块或两者组成。首先执行 try 块中的代码,如果抛出异常,则执行 catch 块中的代码。finally 块中的代码总是在整个结构退出前执行。try { return 42/0; } catch (let e) { // 处理错误 } 也支持以下语法:try { return 42/0; } catch (var e) { // 处理错误 }
try-with-resourcestry-with-resources 语句是一个声明一个或多个资源的 try 语句。try-with-resources 语句确保每个资源在语句结束时被关闭;任何暴露 close() 方法的对象都会调用该方法。let g = open("g"); try(let f = open("f"), g) { // 更多代码 }