前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >怎么在Java 16中编写C风格的局部静态变量

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

作者头像
闻说社
发布2024-07-25 17:02:41
520
发布2024-07-25 17:02:41

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

内层类的静态成员 目前规定,如果一个内层类声明的成员是显性或隐性的静态成员,将是一个编译时错误,除非该成员是一个常量变量。这意味着,例如,一个内类不能声明一个记录类成员,因为嵌套的记录类是隐式静态的。 我们放宽了这个限制,以允许内层类声明显性或隐性的静态成员。特别是,这允许内层类声明一个属于记录类的静态成员。

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

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

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

考虑一下这段代码:

代码语言:javascript
复制
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());
    }
}

它打印出来了:

代码语言:javascript
复制
scss 代码解读复制代码compile(a)
check(a): true
compile(a)
check(b): false

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

代码语言:javascript
复制
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());
    }
}

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

代码语言:javascript
复制
scss 代码解读复制代码compile(a)
check(a): true
check(b): false

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

代码语言:javascript
复制
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());
    }
}

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

代码语言:javascript
复制
scss 代码解读复制代码compile(a)
check(a): true
check(b): false

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

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

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档