怎么在Java 16中编写C风格的局部静态变量

Java 16包括一项改进,通过JEP 395使语言更加规范,该JEP说:

内层类的静态成员

目前规定,如果一个内层类声明的成员是显性或隐性的静态成员,将是一个编译时错误,除非该成员是一个常量变量。这意味着,例如,一个内类不能声明一个记录类成员,因为嵌套的记录类是隐式静态的。

我们放宽了这个限制,以允许内层类声明显性或隐性的静态成员。特别是,这允许内层类声明一个属于记录类的静态成员。

这听起来像是为了使新特性(记录类)更加通用而做的一个小的必要的恶,实际上它有自己的生命。我们可以用它来模仿C风格的局部静态变量,即局部变量:

  • 只初始化一次(而且是懒惰地初始化)
  • 在一个方法的多个执行过程中共享

这听起来是一个相当棘手的功能,即只在本地可见的全局变量。但事实上,这是我长期以来一直想要的东西,特别是当我想在不污染类命名空间的情况下缓存正则表达式模式时。

考虑一下这段代码:

 

typescript

代码解读

复制代码

package p; import java.util.regex.Pattern; public class Test { public static void main(String[] args) { check("a"); check("b"); } static Pattern compile(String pattern) { System.out.println("compile(" + pattern + ")"); return Pattern.compile(pattern); } static void check(String string) { // Re-compiling the pattern every time: Bad // Keeping the pattern local to the method: Good System.out.println("check(" + string + "): " + compile("a").matcher(string).find()); } }

它打印出来了:

 

scss

代码解读

复制代码

compile(a) check(a): true compile(a) check(b): false

如果经常编译一个模式,成本会很高,所以我们最好把它缓存起来。我们过去是这样做的:

 

typescript

代码解读

复制代码

package p; import java.util.regex.Pattern; public class Test { public static void main(String[] args) { check("a"); check("b"); } static Pattern compile(String pattern) { System.out.println("compile(" + pattern + ")"); return Pattern.compile(pattern); } // Compiling the pattern only once: Good // Placing the pattern in a class namespace: Bad static final Pattern P_CHECK = compile("a"); static void check(String string) { System.out.println("check(" + string + "): " + P_CHECK.matcher(string).find()); } }

现在打印的是一个更理想的输出:

 

scss

代码解读

复制代码

compile(a) check(a): true check(b): false

也就是说,正则表达式模式只被编译一次。但不幸的是,我们不得不污染整个类的命名空间,如果我们有几十个这样的正则表达式,这很快就会变得很麻烦。我们能不能把P_CHECK 变量的范围只扩大到check() 方法?我们现在可以了!

 

typescript

代码解读

复制代码

package p; import java.util.regex.Pattern; public class Test { public static void main(String[] args) { check("a"); check("b"); } static Pattern compile(String pattern) { System.out.println("compile(" + pattern + ")"); return Pattern.compile(pattern); } static void check(String string) { // Compiling the pattern only once: Good // Keeping the pattern local to the method: Good // Capturing scope: Egh... var patterns = new Object() { static final Pattern P_CHECK = compile("a"); }; System.out.println("check(" + string + "): " + patterns.P_CHECK.matcher(string).find()); } }

这又一次打印出了所需的、最佳的输出:

 

scss

代码解读

复制代码

compile(a) check(a): true check(b): false

使用var 来使用一个不可取消的类型(其成员我们可以取消引用),再加上将静态成员放在内类中的能力,有效地模拟了局部静态变量,就像在C语言中一样。

由于内层类不太可能逃脱它的作用域,所以它可能捕获作用域的事实并不是什么大的风险,正如之前对双大括号反模式的批评中所说明的那样。你仍然在创建一个额外的类和一个无用的对象,希望逃逸分析能阻止它的分配,所以这并不是一个非常干净的解决方案,但很高兴知道现在可以这样做了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值