views:

1914

answers:

8

In application frameworks I keep seeing frameworks that allow you to pass in multiple Int values (generally used in place of an enum) into a function.

For example:

public class Example
{ 
    public class Values
    {
        public static final int ONE = 0x7f020000;
        public static final int TWO = 0x7f020001;
        public static final int THREE = 0x7f020002;
        public static final int FOUR = 0x7f020003;
        public static final int FIVE = 0x7f020004;
    }

    public static void main(String [] args)
    {
     // should evaluate just Values.ONE
     Example.multiValueExample(Values.ONE);

     // should evalueate just values Values.ONE,  Values.THREE, Values.FIVE
     Example.multiValueExample(Values.ONE | Values.THREE | Values.FIVE);

     // should evalueate just values Values.TWO , Values.FIVE
     Example.multiValueExample(Values.TWO | Values.FIVE);
    }

    public static void multiValueExample(int values){
     // Logic that properly evaluates bitwise values
     ...
    }
}

So what logic should exist in multiValueExample for me to properly evaluate multiple int values being passed in using the bitwise operator?

+9  A: 

Your values should be powers of 2.

That way, you don't lose any information when you bitwise-OR them.

public static final int ONE   = 0x01;
public static final int TWO   = 0x02;
public static final int THREE = 0x04;
public static final int FOUR  = 0x08;
public static final int FIVE  = 0x10;

etc.

Then you can do this:

public static void main(String [] args) {
    Example.multiValueExample(Values.ONE | Values.THREE | Values.FIVE);
}

public static void multiValueExample(int values){
    if(values & Values.ONE == Values.ONE) {
    }

    if(values & Values.TWO == Values.TWO) {
    }

    // etc.
}
Can Berk Güder
Hamid
João da Silva
@Hamid and Joao: thanks for the corrections.
Can Berk Güder
i found the best way to set up the numbers was int ONE = 0x1; int TWO = 0x1 << 1; int THREE = 0x1 <<2; etc
schwiz
+4  A: 

First, you can't define the Values that way to do bitwise comparisons. Instead, set different bits:

public static final int ONE   = 0x1;  // First bit is set
public static final int TWO   = 0x2;  // Second bit is set
public static final int THREE = 0x4;  // Third bit is set
public static final int FOUR  = 0x8;  // Fourth bit is set
public static final int FIVE  = 0x10; // Fifth bit is set

Second, you should probably be using java.util.BitSet for these sorts of operations:

BitSet bits = new BitSet(5);
bits.set(2);
bits.set(4);

System.out.println("these bits are set: " + bits);
// Prints "these bits are set: {2, 4}"

BitSet otherBits = new BitSet(5);
otherBits.set(3);
otherBits.set(4);

System.out.println("these bits are set: " + bits.or(otherBits));
// Prints "these bits are set: {2, 3, 4}"
John Feminella
Is there anything Java doesn't have a class for? =)
Can Berk Güder
Yep! http://stackoverflow.com/questions/639035/making-the-perfect-programming-language/639042#639042 ;)
John Feminella
haha, that function only exists in Python (http://xkcd.com/353/). =)
Can Berk Güder
+2  A: 

The values you combine with | (binary OR, not logical OR [which is ||]) must not have overlapping "1"s in their bit representation. For example,

ONE = 0x1 =   0000 0001
TWO = 0x2 =   0000 0010
THREE = 0x3 = 0000 0011
FOUR = 0x4 =  0000 0100

Then you can combine ONE and TWO, for example:

ONE | TWO = 0000 0011

But you can't distinguish ONE | TWO from THREE, because there are overlapping bits. The numbers you combine should thus be powers of two, such that they don't overlap when OR'ed together. To test if a number was passed in "values", do:

if (values & ONE) {
    // ... then ONE was set
}

To better understand why and how this works, I recommend you read a bit on binary representation and logic. A good place is Chapter 3 of the Art of Assembly.

João da Silva
+2  A: 

You setup the integer values to be powers of two so that each enumerated value is a single bit in the binary representation.

int ONE = 0x1;    //0001
int TWO = 0x2;    //0010
int THREE = 0x4;  //0100
int FOUR = 0x8;   //1000

Then you use bit-wise OR to combine values and bitwise AND to test set values.

int test_value = (ONE | FOUR);   //-> 1001
bool has_one = (test_value & ONE) != 0;  //-> 1001 & 0001 -> 0001 -> true
+2  A: 

Well if they are powers of 2 you would do something like the "display" method in the code below.

Here is a link in wikipedia on the topic as well which should explain why you want powers of 2.

public class Main
{
    private static final int A = 0x01;
    private static final int B = 0x02;
    private static final int C = 0x04;

    public static void main(final String[] argv)
    {
        display(A);
        display(B);
        display(C);
        display(A | A);
        display(A | B);
        display(A | C);
        display(B | A);
        display(B | B);
        display(B | C);
        display(C | A);
        display(C | B);
        display(C | C);
        display(A | A | A);
        display(A | A | B);
        display(A | A | C);
        display(A | B | A);
        display(A | B | B);
        display(A | B | C);
        display(A | C | A);
        display(A | C | B);
        display(A | C | C);
        display(B | A | A);
        display(B | A | B);
        display(B | A | C);
        display(B | B | A);
        display(B | B | B);
        display(B | B | C);
        display(B | C | A);
        display(B | C | B);
        display(B | C | C);
        display(C | A | A);
        display(C | A | B);
        display(C | A | C);
        display(C | B | A);
        display(C | B | B);
        display(C | B | C);
        display(C | C | A);
        display(C | C | B);
        display(C | C | C);
    }

    private static void display(final int val)
    {
        if((val & A) != 0)
        {
            System.out.print("A");
        }

        if((val & B) != 0)
        {
            System.out.print("B");
        }

        if((val & C) != 0)
        {
            System.out.print("C");
        }

        System.out.println();
    }
}
TofuBeer
A: 

The Java Tutorial chapter on bitwise operations are at

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/op3.html

It is very concise but good for reference.

Thorbjørn Ravn Andersen
+1  A: 

Using bit masks were popular when every bit counted. Another way to do this today is to use enums with are simpler to manipulate and extend.

import static Example.Values.*;
import java.util.Arrays;

public class Example {
    public enum Values { ONE, TWO, THREE, FOUR, FIVE }

    public static void main(String [] args) {
        // should evaluate just Values.ONE
        multiValueExample(ONE);

        // should evaluate just values Values.ONE,  Values.THREE, Values.FIVE
        multiValueExample(ONE, THREE, FIVE);

        // should evaluate just values Values.TWO , Values.FIVE
        multiValueExample(TWO, FIVE);
    }

    public static void multiValueExample(Values... values){
        // Logic that properly evaluates
        System.out.println(Arrays.asList(values));
        for (Values value : values) {
            // do something.
        }
    }
}
Peter Lawrey
+3  A: 

As was already mentioned, consider use of enums instead of bit values.

According to Effective Java 2: "Item 32: Use EnumSet instead of bit fields"

Usage of EnumSet is quite effective for memory usage and very convenient.

Here is an example:

package enums;

import java.util.EnumSet;
import java.util.Set;

public class Example {
  public enum Values {
    ONE, TWO, THREE, FOUR, FIVE
  }

  public static void main(String[] args) {
    // should evaluate just Values.ONE
    Example.multiValueExample(EnumSet.of(Values.ONE));

    // should evalueate just values Values.ONE, Values.THREE, Values.FIVE
    Example.multiValueExample(EnumSet.of(Values.ONE, Values.THREE, Values.FIVE));

    // should evalueate just values Values.TWO , Values.FIVE
    Example.multiValueExample(EnumSet.of(Values.TWO, Values.FIVE));
  }

  public static void multiValueExample(Set<Values> values) {
    if (values.contains(Values.ONE)) {
      System.out.println("One");
    }

    // Other checks here...

    if (values.contains(Values.FIVE)) {
      System.out.println("Five");
    }
  }
}
Andrey Vityuk
+1 the most Java-like solution
Joachim Sauer
Yes, thanks for this solution. Unfortunately I'm working with mobile technology where enums take quite a hit in terms of memory management. As such, I'm using bitwise operation to improve preformance.
AtariPete
Agree, in a mobile application it makes sense.
Andrey Vityuk