【问题标题】:& vs && -- how can the first case be used?& vs &&——如何使用第一种情况?
【发布时间】:2011-12-10 11:54:58
【问题描述】:

(a > b) & (c b) 首先评估。如果 (a > b) 为假,则整个表达式为 无论组件的结果如何 (r b) && (c b) 评估为假。这被称为短 电路。

在一本 Java 书籍中看到这一段。我以前一直在用各种语言进行编程,但我从来没有发现需要'&'。如果知道最终结果不受第二个语句的影响,为什么还要评估第二个语句?有什么用吗?是历史原因造成的吗?

同样的问题适用于 |和 ||也是。

【问题讨论】:

  • 谁是er?你有一本印错很严重的书,还是凭记忆打出来的?
  • 我建议你扔掉那本书,它让你的大脑充满了垃圾。正如其他人会告诉你的那样,&&& 之间的区别是 not 评估顺序,并且将 &(a > b) 之类的布尔表达式一起使用是没有意义的。
  • “Java 程序员实用指南”M.Sikora,amazon.com/Java-Practical-Guide-Programmers-Guides/dp/… 第 26 页。直接从书本中拿出来。

标签: java operators semantics


【解决方案1】:
if(0 != ((a > b) ? 1 : 0) & ((c < d) ? 1 : 0)) {
   // but really... (a > b) && (c < d), assuming no side-effects
}

...只需使用 logical operators&amp;&amp;||)作为条件 ;-)这就是它们设计的目的。如果需要非短路行为,则相应地重构代码。

我想我见过一个案例,在这种情况下,&amp; 的使用有些有效,但我不记得它是什么,所以我一定没有发现它有效 ;-) 在像 C/ 这样的语言中在没有谨慎的“布尔”类型的 C++ 中,&amp; 的(输入)和结果可以被处理为0 -&gt; falsenon-0 -&gt; true。然而,可以看出,Java 必须跳过一些乐趣才能获得bool -&gt; int -&gt; bool

bit-wise operator 的唯一理由是,按位操作,IMOHO。在执行某种编码(包括“位域”和“位掩码”)时,按位运算符最有用。在处理 Java 的仅签名字节等带来的乐趣时,它们也很有用。

我认为更大的(唯一的?)要点是 &amp;&amp;|| 是短路的——它们实际上是 唯一的运算符 有这种行为(不包括?: 的参数);剩下的只是解释位运算符的急切行为。这只是为了重新执行规则:不要在条件句中引起副作用(除了一些广为接受的习语,但即便如此,也要保持简单)。

编码愉快。


按位使用示例:

想象一下使用以序列化格式存储在单个“整数”槽中的标志:

int flags = 0;
if (this.encypted) {
   flags |= EncryptedMode;
}
out.write(flags);

// later on
int flags = in.readInt();
this.encrypted = (flags & EncryptedMode) != 0;

读取一个字节的“无符号值”:

byte[] data = {-42, ...}; // read in from file or something
int unsignedByte = data[0] & 0xFF;

【讨论】:

    【解决方案2】:

    '&' 和 '&&' 之间的区别并不为人所知,书中的那个例子也没有多大帮助。

    这是另一个展示短路工作原理的示例(使用具有副作用的可怕方法,但这不是重点)。

    想象一下你有这个:

    private int cnt;
    
    private boolean a() {
        cnt++;
        return false;
    }
    
    private boolean b() {
        cnt++;
        return false;
    }
    

    如果执行以下操作:

        cnt = 0;
        if ( a() && b() ) {}
        System.out.println( cnt );
    

    它应该打印 1。

    如果你执行以下操作:

        cnt = 0;
        if ( a() & b() ) {}
        System.out.println( cnt );
    

    它应该打印 2。因为在后一种情况下 b() 必须根据语言规范进行评估,而在第一种情况下 b() 不得根据语言规范进行评估。

    【讨论】:

    • 对“棘轮怪胎”的回答 +1 给出了一个示例,说明您何时可能想要使用此类结构。
    【解决方案3】:

    使用非短路运算符可以通过避免分支错误预测停顿(很容易达到十几个或更多时钟周期)来加速性能关键代码。

    【讨论】:

      【解决方案4】:

      也许第二次评估采用赋值语句或方法调用的形式,在这种情况下,您可能希望它执行。我不会使用按位运算符代替这样的逻辑运算符。如果您需要通过 &amp;&amp; 执行某些操作,请在您的逻辑语句之前执行此操作并将结果存储在变量中。

      【讨论】:

        【解决方案5】:

        如果您希望您的代码受到timing attacks 的攻击,您希望尽可能少的分支(条件执行路径),这是消除它们的一种方法

        【讨论】:

          【解决方案6】:

          您可以在必须评估两个子表达式的情况下使用&amp;。例如,如果它们都具有您的应用程序的其余部分可以观察到的副作用。

          【讨论】:

            【解决方案7】:

            && operator 由 Java 语言规范定义,用于执行短路评估。

            但是,& 运算符不是 even when applied to boolean arguments

            如果其中一个参数具有您不希望短路的副作用,您可以利用这一点。但是,根据我的经验,这并不常见,而且您将面临有人“修复”它的风险。最好分成几个步骤。例如,而不是:

            if ( foo() & bar() ) {... }
            

            你可以说:

            boolean isFoo = foo();
            boolean isBar = bar();
            if ( isFoo && isBar ) { ... }
            

            【讨论】:

              【解决方案8】:

              您的书令人困惑。在大多数情况下,您只会使用 '&&' 和 '||'。单独的 '&' 和 '|' 是按位运算符 - 您可以在此处阅读有关它们的更多信息:http://download.oracle.com/javase/tutorial/java/nutsandbolts/op3.html

              【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-10-14
              • 2019-12-12
              • 1970-01-01
              • 1970-01-01
              • 2022-01-22
              • 2011-11-01
              • 2015-10-04
              相关资源
              最近更新 更多