检查断言是否启用

问题描述 投票:0回答:4

您可以在

assert
 上启用/禁用 
ClassLoader

但是如何确定它们是否已启用?

(我想采用一些代码路径,仅当在启用断言的情况下调用 JVM 时才执行昂贵的检查。)

java assert
4个回答
15
投票
public static boolean areAssertsEnabled() {
  boolean assertsEnabled = false;
  assert assertsEnabled = true; // Intentional side effect!!!
  return assertsEnabled;
}

来源

参见 “要求启用断言”


5
投票
boolean assertEnabled = false;

try {
   assert false;
} catch (AssertionError e) {
   assertEnabled = true;
}

2
投票
ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-ea");

0
投票

兄弟姐妹的答案是正确的。但我质疑这种方法的实用性和普遍性。 (跳转至“替代方法”,了解解决此问题的另一种方法。)

启用断言的最简单方法是为所有类启用它们。

-ea

或:

-enableassertions

在这种情况下,您可以将该事实存储在一个变量中并在整个程序中使用它:

public class Main {

    public static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }
[…]
}

但是说我有课

Main, A, B, C

并且:

-ea:Main -ea:A

即仅对

Main
A
启用断言。因此,意图必须是不应该运行
B
C
内部的断言。

鉴于此:

public class Main {

    public static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }
    public static void main(String[] args) {
        System.out.println("Hello from main()");
        m();
        assert A.print();
        A.print2();
        assert B.print();
        B.print2();
        assert C.print();
        C.print2();
    }

    private static void m() {
        if (assertsEnabled) {
            System.out.println("  main() again (using static variable)");
        }
    }
}

很清楚如何处理

print()
方法:它们将从
-ea:Main
开始运行。如果
-da:Main()
那么它们将不会运行。

m()
将打印字符串,因为我们知道
assertsEnabled

print2()
函数如下所示:

// C
    public static void print2() {
        if (Main.assertsEnabled) {
            System.out.println("  assert inside C (using variable from Main)");
        }
    }

在这里,会发生什么也很清楚:程序将打印自

-ea:Main
以来的字符串以及我们初始化
Main.assertsEnabled
的方式。但请稍等:断言对于
C
是禁用的(实际上是
-da:C
)。那么这真的是我们想要的吗?也许。或者也许我们只是使用属于
Main
的静态变量,因为它足够方便,并没有考虑到这个 运行在
Main
:


    public static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }

与复制粘贴到

C
中的完全相同的代码的行为不同。

因此,根据 other 类的断言包含而采取不同行为的代码似乎可能会令人困惑。让我们将这段代码复制粘贴到每个使用断言的类中:

    private static boolean assertsEnabled = false;
    static {
        assert assertsEnabled = true;
    }

并像这样使用它:

if (assertsEnabled) {
  // Error checking
}

但我认为有一种更直接的方法。

替代方法

操作:

我想采用一些代码路径,仅当在启用断言的情况下调用 JVM 时才执行昂贵的检查。

  1. 对于任何代码块X,只有在启用断言的情况下才应该运行
  2. 创建一个带有返回类型的静态方法
    x()
    boolean
  3. 只需放置
    return true
    来满足类型检查器的要求(也可以是您想要断言的任何内容,但由于您想检查断言是否已启用,然后运行一些代码,似乎检查比单个检查更复杂布尔表达式可以方便实现)
  4. 将X放入方法体中
  5. assert
     放在所有 
    x()
     的调用前面
    
assert x(); […] private static boolean x() { // X }
例如:

private static boolean x() { var setup = new Setup(); assert ...; assert ...; [more setup and preparation] assert ...; return true; }
交错常规代码和断言代码

“运行时间”问题:有时您会遇到跨领域的问题。在这种情况下,您可能想要运行一些仅断言代码,然后是常规代码,最后是仅断言代码的另一部分(使用第一部分)。

关于断言的 Java 文章介绍了如何解决这个问题:

有时需要在执行计算之前保存一些数据以检查后置条件。您可以使用两个断言语句和一个简单的内部类来完成此操作,该内部类保存一个或多个变量的状态,以便在计算后检查(或重新检查)它们。 […]

这是一个更简单且手动的示例:

private static void doWork(Work work) { ConsistencyCheck cc = null; assert ((cc = new ConsistencyCheck(work)) != null); doWorkInner(work); assert cc.check(work); }
在禁用断言的情况下运行时,这里唯一的开销(如果 JIT 没有将其作为死代码删除)是将对象初始化为 

null

,这应该不会很昂贵。

© www.soinside.com 2019 - 2024. All rights reserved.