使用java.lang.Boolean和switch实现三进制逻辑

4

java.lang.Boolean非常适合处理三态逻辑,因为它确切地有三个状态:Boolean.TRUE(是这种情况),Boolean.FALSE(不是这种情况)和null(我们不知道情况如何)。使用switch语句来处理这个问题是一个很好的设计,例如在这个构造函数中:

public class URN {
private String value = null;    

public URN (String value, Boolean mode){
    switch (mode){
        case TRUE:
            if(!isValidURN(value))
                throw new MalformedURLException("The string could not be parsed.");
            this.value = value;
        break;
        case FALSE:
            this.value = value.concat(checkByteFor(value));
        break;
        case null:
            if(isValidURN(value))
                this.value = value;
            else
                this.value = value.concat(checkByteFor(value));
        break;
    }
    return;
}

不幸的是,Java不允许这样做,会抱怨“无法切换到布尔类型的值”。实现这个功能会导致混淆的控制流和不友好的代码:

public URN (String value, Boolean mode){
    Boolean valid = null;
    if (!Boolean.FALSE.equals(mode)){
        valid = isValidURN(value);

        if (Boolean.TRUE.equals(mode) && !valid)
                throw new MalformedURLException("The string could not be parsed.");

        if(Boolean.TRUE.equals(valid)) {
            this.value = value;
            return;
    }   }

    this.value = value.concat(checkByteFor(value));
}

以友好的方式实现需要实现一个枚举类(在实际应用中比这个例子更复杂,因为必须重写.equals()方法,使Trinary.NULL.equals(null)变为true),并进行转换:

private enum Trinary {TRUE, FALSE, NULL};
public URN (String value, Boolean toConvert, String x){

    Trinary mode;
    if(toConvert == null)
        mode = Trinary.NULL;
    else
        mode = toConvert.equals(Boolean.TRUE) ? Trinary.TRUE : Trinary.FALSE;

    switch (mode){
        case TRUE:
            if(!isValidURN(value)) throw new MalformedURLException("The string could not be parsed.");
            this.value = value;
        break;
        case FALSE:
            this.value = value.concat(checkByteFor(value));
        break;
        case NULL:
            if(isValidURN(value))
                this.value = value;
            else
                this.value = value.concat(checkByteFor(value));
        break;
    }
    return;
}

在我看来,这是一种更好、更易读的解决方案,但原始方法代码大小的另一半仅用于转换,这让人感到烦恼,在现实生活中你必须关心具有相同语义的两个不同空值。有没有更好的方法来做到这一点?

这里可能会有人添加一个“三值逻辑”标签 :) - Matthias Ronge
4
实际上,它叫做“三进制”;-) - darioo
更好的方法:不要让NULL等于null,并且一开始就不要使用null - Louis Wasserman
2个回答

6
使用null对象传递此类信息并不理想。请记住,您无法对空对象进行任何方法调用,这意味着如果将来您需要调用.getClass、.equals、.compare等方法,则必须重写代码。
最佳选择肯定是采用枚举选项。
enum Ternary {TRUE,FALSE,UNKNOWN}

您可以进一步扩展该类,以便具有获取此类对象的方法。
public Ternary getByValue(Boolean o) {
    if(o == null)
        return UNKNOWN;
    if(o)
        return TRUE;
    return FALSE;
}

2

我同意,switch不支持null或者如果没有提到就将其视为default是很烦人的。

注意:三元运算符可以是NULLnull,这可能会让人感到困惑。

与其使用true、false和null,我建议使用有意义的模式名称。例如,使用VALIDATING、CONCATENATING、MIXED或更合适的名称。

最简单的解决方案是:

public URN (String value, Boolean mode){
    if (mode == null) {
        this.value = isValidURN(value) ? values : value.concat(checkByteFor(value));
    } else if (mode) {
        if(!isValidURN(value))
            throw new MalformedURLException("The string could not be parsed.");
        this.value = value;
    } else {
        this.value = value.concat(checkByteFor(value));
    }
    return;
}

顺便提一下,与TRUE进行比较可能会令人困惑。

Boolean b = new Boolean(true);
if (b == Boolean.TRUE) // is false !!!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接