如何以编程方式启用断言?

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

如何以编程方式为特定类启用断言,而不是指定命令行参数“-ea”?

public class TestAssert {

    private static final int foo[] = new int[]{4,5,67};


    public static void main(String []args) {
        assert foo.length == 10;
    }
}
java configuration assertions
5个回答
11
投票

尝试

ClassLoader loader = getClass().getClassLoader();
setDefaultAssertionStatus(true);

ClassLoader.getSystemClassLoader().setDefaultAssertionStatus(true);

编辑:

基于评论

    ClassLoader loader = ClassLoader.getSystemClassLoader();
    loader.setDefaultAssertionStatus(true);
    Class<?> c = loader.loadClass("MyClass");
    MyClass myObj = (MyClass) c.newInstance();


public class MyClass {

    private static final int foo[] = new int[]{4,5,67};
    MyClass()
    {
        assert foo.length == 10;
    }
}

9
投票

这是对@bala 好的答案的评论,但它太长了。

如果您只是启用断言,然后调用您的主类 - 您的主类将在启用断言之前加载,因此您可能需要一个不直接引用代码中其他任何内容的加载器。 它可以设置断言,然后通过反射加载其余代码。

如果在加载类时未启用断言,那么它们应该立即“编译出来”,这样您就无法打开和关闭它们。 如果你想切换它们,那么你根本不需要断言。

由于运行时编译,会出现这样的情况:

public myAssertNotNull(Object o) {
    if(checkArguments) 
        if(o == null)
            throw new IllegalArgumentException("Assertion Failed");
}

应该几乎与断言一样快,因为如果代码被执行很多并且 checkArguments 为 false 并且不改变,那么整个方法调用可以在运行时编译出来,这将具有与断言相同的基本效果(此性能取决于在虚拟机上)。


2
投票

可以使用 reflection 启用或禁用断言。与反射一样,该解决方案很脆弱,可能并不适合所有使用场景。但是,如果适用且可接受,它比

setClassAssertionStatus
更灵活,因为它允许在执行中的各个点启用/禁用断言检查,甚至在类初始化之后

此技术需要编译器生成一个合成静态字段来指示是否启用断言。例如,javac 和 Eclipse 编译器都会为任何包含

$assertionsDisabled
语句的类生成字段
assert

这可以通过以下方式验证:

public class A {
    public static void main(String[] args) {
        assert false;
        System.out.println(Arrays.toString(A.class.getDeclaredFields()));
    }
}

设置所需的断言状态只需设置此字段(注意反转的布尔值):

// Helper method in any class
public static void setAssertionsEnabled(Class<?> clazz, boolean value) 
    throws ReflectiveOperationException
{
    Field field = clazz.getDeclaredField("$assertionsDisabled");
    field.setAccessible(true);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(Test.class, !value);
}

0
投票

最简单、最好的方法是:

public static void assertion(boolean condition, String conditionFailureMessage)
{
    if(!condition)
        throw new AssertionError(conditionFailureMessage);
}

无需将 -ea 设置为 VM 参数。

调用函数如下:

assertion(sum>=n,"sum cannot be less than n");

如果断言失败,代码将给出 AssertionError,否则代码将安全运行。


0
投票

这个问题已经很老了,对于当今任何偶然发现这个问题的人来说,答案仍然是否定的,你无法在运行时可靠地启用断言。

但是您可以做的是实现以下内容并确保在运行时启用断言(如果您想强制执行):

private static void ensureAssertionsAreEnabled() {
    try {
        assert false;
    } catch (AssertionError error) {
        return;
    }

    throw new AssertionsNotEnabledError();
}

然后添加自定义错误类:

public class AssertionsNotEnabledError extends Error {

    public AssertionsNotEnabledError() {
        super("Assertions must be enabled for this application to function correctly. " +
                "Please use the -ea flag as a VM argument when running the application.");
    }
}

只记得调用ensureAssertionsAreEnabled();作为 Main.java 中的第一件事:

public class Main {
    public static void main(String[] args) {
        ensureAssertionsEnabled();
    }
}

这是做什么的:

它尝试强制一个 AssertionError ,只有在启用断言时才会抛出该错误,因此,如果未启用断言,则不会抛出任何错误,并且忽略捕获,从而触发抛出 AssertionsNotEnabledError 。

但是,如果启用了断言,则会抛出 AssertionError 并且捕获将简单地返回,忽略下面的错误。

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