views:

443

answers:

5

I have a long set of comparisons to do in Java, and I'd like to know if one or more of them come out as true. The string of comparisons was long and difficult to read, so I broke it up for readability, and automatically went to use a shortcut operator |= rather than negativeValue = negativeValue || boolean.

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

I expect negativeValue to be true if any of the default<something> values are negative. Is this valid? Will it do what I expect? I couldn't see it mentioned on Sun's site or stackoverflow, but Eclipse doesn't seem to have a problem with it and the code compiles and runs.

+7  A: 

It's not a "shortcut" (or short-circuiting) operator in the way that || and && are (in that they won't evaluate the RHS if they already know the result based on the LHS) but it will do what you want in terms of working.

As an example of the difference, this code will be fine if text is null:

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

whereas this won't:

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

(Obviously you could do "".equals(text) for that particular case - I'm just trying to demonstrate the principle.)

Jon Skeet
A: 
List<Integer> params = Arrays.asList (defaultStock, defaultWholesale, 
                                       defaultRetail, defaultDelivery);
int minParam = Collections.min (params);
negativeValue = minParam < 0;
Roman
I think I'd prefer `negativeValue = defaultStock < 0 || defaultWholesale < 0` etc. Aside from the inefficiency of all the boxing and wrapping going on here, I don't find it nearly as easy to understand what your code would really mean.
Jon Skeet
I he has even more then 4 parameters and the criterion is the same for all of them then I like my solution, but for the sake of readability I would separate it into several lines (i.e. create List, find minvalue, compare minvalue with 0).
Roman
That does look useful for a large number of comparisons. In this case I think the reduction in clarity isn't worth the saving in typing etc.
Dr. Monkey
+8  A: 

The |= is a compound assignment operator (JLS 15.26.2) for the boolean logical operator | (JLS 15.22.2); not to be confused with the conditional-or || (JLS 15.24). There are also &= and ^= corresponding to the compound assignment version of the boolean logical & and ^ respectively.

In other words, for boolean b1, b2, these two are equivalent:

 b1 |= b2;
 b1 = b1 | b2;

The difference between the logical operators (& and |) compared to their conditional counterparts (&& and ||) is that the former do not "shortcircuit"; the latter do. That is:

  • & and | always evaluate both operands
  • && and || evaluate the right operand conditionally; the right operand is evaluated only if its value could affect the result of the binary operation. That means that the right operand is NOT evaluated when:
    • The left operand of && evaluates to false
      • (because no matter what the right operand evaluates to, the entire expression is false)
    • The left operand of || evaluates to true
      • (because no matter what the right operand evaluates to, the entire expression is true)

So going back to your original question, yes, that construct is valid, and while |= is not exactly an equivalent shortcut for = and ||, it does compute what you want. Since the right hand side of the |= operator in your usage is a simple integer comparison operation, the fact that | does not shortcircuit is insignificant.

There are cases, when shortcircuiting is desired, or even required, but your scenario is not one of them.

It is unfortunate that unlike some other languages, Java does not have &&= and ||=. This was discussed in the question Why doesn’t Java have compound assignment versions of the conditional-and and conditional-or operators? (&&=, ||=).

polygenelubricants
+1, very thorough. it seems plausible that a compiler might well convert to a short-circuit operator, if it could determine that the RHS has no side effects. any clue about that?
Carl
I read that when RHS is trivial and SC is not necessary, the "smart" SC operators are actually a bit slower. If true, then it's more interesting to wonder if some compilers can convert SC to NSC under certain circumstances.
polygenelubricants
+1  A: 

You could just have one statement.

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

For simplest expressions, using | can be faster than || because even though it avoids doing a comparison it means using a branch implicity and that can be many times more expensive.

Peter Lawrey
I did start with just one, but as stated in the original question I felt that "The string of comparisons was long and difficult to read, so I broke it up for readability".That aside, in this case I'm more interested in learning the behaviour of |= than in making this particular piece of code work.
Dr. Monkey
A: 

Though it might be overkill for your problem, the Guava library has some nice syntax with Predicates and does short-circuit evaluation of or/and Predicates.

Essentially, the comparisons are turned into objects, packaged into a collection, and then iterated over. For or predicates, the first true hit returns from the iteration, and vice versa for and.

Carl