Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 用于断言实现的表达式的字符串表示形式_Java_Android_Assert - Fatal编程技术网

Java 用于断言实现的表达式的字符串表示形式

Java 用于断言实现的表达式的字符串表示形式,java,android,assert,Java,Android,Assert,由于Java的assert关键字在Android上,因此我将实现一个断言类,该类也可以配置为在发布版本中检查断言 现在我可以做一些类似的事情: MyAssertion.assert(a != 2) 当表达式为false时,它抛出一个断言异常。但是如何获取表达式的字符串表示形式以传递到错误消息?唯一的方法是向assert方法添加字符串参数: MyAssertion.assert(a != 2, "a must not be equal to 2"); 作为assert的输入,您得到的是true

由于Java的
assert
关键字在Android上,因此我将实现一个断言类,该类也可以配置为在发布版本中检查断言

现在我可以做一些类似的事情:

MyAssertion.assert(a != 2)

当表达式为false时,它抛出一个断言异常。但是如何获取表达式的字符串表示形式以传递到错误消息?

唯一的方法是向
assert
方法添加字符串参数:

MyAssertion.assert(a != 2, "a must not be equal to 2");
作为
assert
的输入,您得到的是true或false,因此您无法从中构建代表性字符串

否则,您可以像这样实现
assert

MyAssertion.assertNotEquals(a, 2);
当这失败时,您知道这是因为您测试的值等于2,并且您可以构建一条信息性消息(尽管您不知道具体什么值等于2)


如果您希望以某种方式从断言中构造有意义的消息,我认为唯一可行的方法就是构造一个字符串表达式,让JavaScript引擎对其求值,并在表达式求值为
false
时生成一条消息。请注意,这会降低很多性能,因为启动JavaScript引擎需要很多时间。这可以通过在生产中禁用断言的机制来解决

下面是一个例子。注意,我使用的是新的Java8NashornJavaScript引擎,但这应该适用于旧的Rhino

用法示例:

int value = 3;
String str = "test";
Assertions.assertTrue("$1 == 3", value);
Assertions.assertTrue("$1 == 3 && $2 == 'test'", value, str);
Assertions.assertTrue("$1 == 4 && $2 == 'test'", value, str);
这将抛出第三个断言:

断言失败:3==4&&“测试”==“测试”

其思想是,您可以编写任何JavaScript友好的表达式,这些表达式可以计算为布尔值。占位符
$i
将替换为方法的参数(
$1
将替换为第一个参数,以此类推)

这是一节课。它可以改进(处理错误情况,如参数不足等),但这应该足以让您开始

public final class Assertions {

    private static final ScriptEngine ENGINE = new ScriptEngineManager().getEngineByName("nashorn");

    private Assertions() { }

    public static void assertTrue(String expression, Object... values) {
        for (int i = 0; i < values.length; i++) {
            ENGINE.put("$" + (i+1), values[i]);
        }
        try {
            boolean pass = (Boolean) ENGINE.eval(expression);
            if (!pass) {
                for (int i = 0; i < values.length; i++) {
                    expression = expression.replace("$" + (i+1), stringRepresentation(values[i]));
                }
                throw new AssertionError("An assertion has failed: " + expression);
            }
        } catch (ScriptException e) {
            throw new InternalError(e);
        } finally {
            for (int i = 0; i < values.length; i++) {
                ENGINE.getBindings(ScriptContext.ENGINE_SCOPE).remove("$" + (i+1));
            }
        }
    }

    private static String stringRepresentation(Object o) {
        if (o instanceof String) {
            return "'" + o + "'";
        }
        return o.toString();
    }

}
公共最终类断言{
私有静态最终ScriptEngine引擎=新ScriptEngineManager().getEngineByName(“nashorn”);
私有断言(){}
公共静态void assertTrue(字符串表达式、对象…值){
对于(int i=0;i
(1)使用简单,但难以实现。需要Java8。可以使用lambda表达式:

Assert.isTrue(() => a != 2)
在评估失败时,您的Assert.isTrue方法的实现应该重复IDE所做的所有步骤—(a)发现lambda类的字节码,(b)反编译,例如使用JAD,(c)发现源代码(如果可用)

(2) 易于使用,易于实现,但不能完全满足您的需求。您可以使用代码样式规则检查并强制使用正确的断言。一个regexp将检查没有单参数断言,第二个(使用regexp back refs)将检查代码和文本描述是否相似

(3) 易于使用,易于实现,但依赖于构建系统。您可以在项目构建期间自动检查和修复源代码


例如,对于Maven build system,您可以创建自己的插件来检查和修复process sources阶段上源代码中的断言使用情况。

我认为您无法访问传递给方法调用的内部java表达式

但是,您可以使用一些表达式语言库,并为断言实现执行自定义表达式处理

以下是一些表达式语言库的列表:


希望有帮助:)

注释处理可以做到这一点。您需要创建一个注释,例如
@InlineAssertExpressions
。然后编写一个处理器,解析源文件并创建一个表示表达式的字符串,并将其添加到对assert方法的调用中,您可以重载该方法以获取可选的字符串参数。这种方式在性能方面是非常优化的,因为内联发生在编译时。注释处理有点被忽略了,但我认为这是一个很好的用途。

assertEquals
assertNotEquals
可能是基本表达式的解决方案。您能解释什么是根本性的问题,或者至少提供一个链接吗?@Axel,当然。添加了一个源代码。只是一个建议,因为您正在开始一些新的东西-看看Guava的先决条件。有没有理由不使用jUnit对您的发布进行单元测试?否则,断言通常只是生产代码中的错误实践。谢谢您的回答。这两种方法都是我不想做的妥协:第一种方法需要源代码中的冗余信息。每当我改变等式时,我都需要注意使文本适应它。编写琐碎的文本也无益于浪费开发人员的时间。第二种方法要求对所有类型的方程采用不同的方法,这种方法不酷,但可以接受。更大的问题是可读性:
a==2
vs.
a!=2
a!=null
比不同的断言函数名更容易阅读。不过,谢谢你。这可能是我能做的最好的了