代码之家  ›  专栏  ›  技术社区  ›  David Mason

Java中的快捷方式“或赋值”(=)运算符

  •  79
  • David Mason  · 技术社区  · 15 年前

    我在爪哇有一个很长的比较,我想知道他们中的一个或多个是否是真的。比较字符串很长,很难读取,所以为了可读性,我将其拆分,然后自动使用快捷运算符。 |= 而不是 negativeValue = negativeValue || boolean .

    boolean negativeValue = false;
    negativeValue |= (defaultStock < 0);
    negativeValue |= (defaultWholesale < 0);
    negativeValue |= (defaultRetail < 0);
    negativeValue |= (defaultDelivery < 0);
    

    我期待 negativeValue 如果任何默认<something>值为负,则为真。这是有效的吗?它会像我期望的那样吗?我在Sun的网站或StackOverflow上看不到它的相关内容,但Eclipse似乎不存在任何问题,代码可以编译和运行。


    同样,如果我想执行几个逻辑交叉,我可以使用 &= 而不是 && ?

    8 回复  |  直到 6 年前
        1
  •  188
  •   Community CDub    8 年前

    这个 |= 是复合赋值运算符( JLS 15.26.2 )对于布尔逻辑运算符 | ( JLS 15.22.2 )不与条件或 || ( JLS 15.24 )也有 &= ^= 对应于布尔逻辑的复合赋值版本 & ^ 分别。

    换句话说,对于 boolean b1, b2 ,这两个相等:

     b1 |= b2;
     b1 = b1 | b2;
    

    逻辑运算符之间的区别( & γ )与有条件的对手相比( && γ )即前者不“短路”;后者不“短路”。即:

    • & γ 总是 计算两个操作数
    • && γ 计算右操作数 有条件地 ;只有当右操作数的值可能影响二进制运算的结果时,才计算右操作数。这意味着在以下情况下不计算右操作数:
      • 的左操作数 && 评估为 false
        • (因为无论右操作数的计算结果如何,整个表达式都是 )
      • 的左操作数 γ 评估为 true
        • (因为无论右操作数的计算结果如何,整个表达式都是 )

    回到你最初的问题,是的,这个结构是有效的,而 = 不是完全等效的快捷方式 = γ 它可以计算出你想要的。因为右手边的 = 您使用的运算符是一个简单的整数比较运算,事实上 γ 不短路是无关紧要的。

    有些情况下,需要短路,甚至需要短路,但您的场景不是其中之一。

    不幸的是,与其他语言不同,Java没有。 &&= ||= . 这个问题已经讨论过了 Why doesn't Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=) .

        2
  •  16
  •   Jon Skeet    15 年前

    它不是一个“快捷方式”(或短路)操作员,就像和&那样(因为如果他们已经知道基于lhs的结果,他们不会评估rhs),但它将按照您的要求执行 工作 .

    作为区别的一个例子,如果 text 为空:

    boolean nullOrEmpty = text == null || text.equals("")
    

    然而,这不会:

    boolean nullOrEmpty = false;
    nullOrEmpty |= text == null;
    nullOrEmpty |= text.equals(""); // Throws exception if text is null
    

    (显然你可以 "".equals(text) 对于那个特定的案例,我只是想演示一下这个原理。)

        3
  •  3
  •   blo0p3r Chen Noam    10 年前

    你只要一句话。它在多行上表示,读起来几乎与您的示例代码完全相同,只是命令性较低:

    boolean negativeValue
        = defaultStock < 0 
        | defaultWholesale < 0
        | defaultRetail < 0
        | defaultDelivery < 0;
    

    对于最简单的表达式,使用 | 可以比 || 因为即使它避免进行比较,它也意味着隐式地使用分支,这可能要花费很多倍。

        4
  •  1
  •   Carl    15 年前

    尽管这可能会对你的问题造成过度伤害, Guava 图书馆有一些很好的语法 Predicate s和do短路评估或/和 谓语 S.

    本质上,比较被转换成对象,打包成一个集合,然后迭代。对于或谓词,第一个真正命中从迭代返回,反之亦然。

        5
  •  1
  •   Krzysztof Jabłoński    12 年前

    如果是关于可读性的话,我已经有了将测试数据与测试逻辑分离的概念。代码示例:

    // declare data
    DataType [] dataToTest = new DataType[] {
        defaultStock,
        defaultWholesale,
        defaultRetail,
        defaultDelivery
    }
    
    // define logic
    boolean checkIfAnyNegative(DataType [] data) {
        boolean negativeValue = false;
        int i = 0;
        while (!negativeValue && i < data.length) {
            negativeValue = data[i++] < 0;
        }
        return negativeValue;
    }
    

    这段代码看起来更冗长,也更容易解释。甚至可以在方法调用中创建数组,如下所示:

    checkIfAnyNegative(new DataType[] {
        defaultStock,
        defaultWholesale,
        defaultRetail,
        defaultDelivery
    });
    

    它比“比较字符串”更可读,而且还具有短路的性能优势(以数组分配和方法调用为代价)。

    编辑: 使用varargs参数可以简单地实现更高的可读性:

    方法签名为:

    boolean checkIfAnyNegative(DataType ... data)
    

    电话看起来是这样的:

    checkIfAnyNegative( defaultStock, defaultWholesale, defaultRetail, defaultDelivery );
    
        6
  •  1
  •   oxyt    6 年前

    这是一篇老文章,但为了给初学者提供一个不同的视角,我想举个例子。

    我认为类似复合运算符最常见的用例是 += .我相信我们都写了这样的东西:

    int a = 10;   // a = 10
    a += 5;   // a = 15
    

    这有什么意义?重点是避免样板文件和消除重复的代码。

    所以,下一行的操作完全相同,避免键入变量 b1 同一行两次。

    b1 |= b2;
    
        7
  •  0
  •   Roman    15 年前
    List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                           defaultRetail, defaultDelivery);
    int minParam = Collections.min (params);
    negativeValue = minParam < 0;
    
        8
  •  0
  •   oneklc    12 年前

    ||逻辑布尔或
    按位或

    |=按位包含或与赋值运算符

    =不短路的原因是它执行的是位或非逻辑或。 这就是说:

    C |= 2 is same as C = C | 2
    
    

    Tutorial for java operators

    推荐文章