Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using shorter version of or "||" in an If statement with integers and Math/Logic error?

So I finally got my code to work with:

if((choice == 1 ) || (choice == 2) || (choice == 3) || (choice == 4)){

but why does:

if(choice == (1 | 2)) {

result in a logic/math error? for example, if I enter "3" then the code accepts it and processes it as successful. The code snippet is as follows:

while(counter == 0){
        try{
            int choice = Integer.parseInt(input.nextLine());

            if(choice == (1 | 2)){
                System.out.println("You got it!");
                ++counter;
            }else{
                System.out.println("Try again");
            }
        }
        catch(NumberFormatException Exception){
            System.out.println("You did something wrong");
        }


    }

And if I do:

if(choice == (1 | 2 | 3 | 4 )){

then it will only accept 7 as far as I can tell. What exactly is going on when it is compiling and is there a way to shorten the solution I found?

like image 434
Paul Avatar asked Nov 26 '25 05:11

Paul


2 Answers

The issue here is that

if (choice == (1 | 2)) { ... }

doesn't mean "if choice is equal to one or equal to two, then... ." Instead, Java is interpreting 1 | 2 as "the bitwise OR of the two numbers 1 and 2," since a single vertical bar represents the bitwise OR operator. If you take the bitwise OR of 1 and 2, you get the number 3 (if you know about binary numbers, see if you can confirm why this is the case), so your if statement is completely equivalent to

if (choice == 3) { ... }

which is why you're seeing the behavior that you're seeing.

Similarly, if you write

if (choice == (1 | 2 | 3 | 4)) { ... }

Java interprets the expression 1 | 2 | 3 | 4 as "the bitwise OR of the numbers 1, 2, 3, and 4," which works out to 7.

If you have a collection of values and you want to test if a specific value is equal to any of those values, one option is, as you've noted, to have a bunch of independent equality tests. If you have a very large number of values, you may want to use something like a HashSet instead.

like image 98
templatetypedef Avatar answered Nov 28 '25 20:11

templatetypedef


The expression 1 | 2 is a bitwise OR, so the result is 3, and if(choice == (1 | 2)) is actually the same as if(choice == 3).

The | only acts as a logical OR between boolean values.

See also the Java Language Specification, section 15.22.1 Integer Bitwise Operators &, ^, and |:

When both operands of an operator &, ^, or | are of a type that is convertible (§5.1.8) to a primitive integral type, binary numeric promotion is first performed on the operands (§5.6.2).

The type of the bitwise operator expression is the promoted type of the operands.

[..]

For |, the result value is the bitwise inclusive OR of the operand values.

and section 15.22.2 Boolean Logical Operators &, ^, and |

When both operands of a &, ^, or | operator are of type boolean or Boolean, then the type of the bitwise operator expression is boolean. In all cases, the operands are subject to unboxing conversion (§5.1.8) as necessary.

[..]

For |, the result value is false if both operand values are false; otherwise, the result is true.

As to a shorter solution, trivially your initial code is probably as simple as it can get. If you want to scale it to a larger number of conditions, then consider:

  • 1 <= choice && choice <= 4 - if accepted values of choice are a contiguous range
  • Arrays.binarySearch(new int[1, 2, 3, 4], choice) >= 0 - requires that the array is sorted
  • Arrays.asList(1, 2, 3, 4).contains(choice) - this has overhead, because this converts the integer values to objects.
  • Convert your code to a switch (not immediately shorter, until we get pattern-matching switch in a future Java version, but can be clearer with a lot of values)

    switch(choice) {
    case 1:
    case 2:
    case 3:
    case 4:
        // if 1, 2, 3, 4
        // do things
        break;
    case 5:
        // else if 5
        // do other things
        break
    default:
        // else
        // do something else
        break;
    }
    

Except the first and the last, these options have the downside that it is not immediately clear what you are checking for. In those case, clear code trumps 'short' code.

like image 26
Mark Rotteveel Avatar answered Nov 28 '25 19:11

Mark Rotteveel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!