How to set required constants for methods? - java

I am creating a method called setState and I want to use binary operators for it, but I want to create something to check if the passed argument is a constant defined in the class:
public static final int STATE1 = 0b1;
public static final int STATE2 = 0b10;
public static final int STATE3 = 0b100;
public void setState(int stateType, boolean state){
if(state){
this.state |= stateType;
}else{
this.state &= ~stateType;
}
}
So when I type setState(10, false) it will say: Wrong argument type, found x, required y

you only want stateType to be one of STATE1, STATE2, or STATE3?
You could use an enum defined in that class. Something like:
public class MyClass{
public enum State{
STATE1 (0b1),
STATE2(0b10),
STATE3(0b100);
public final int value;
State(int value){
this.value = value;
}
}
public void setState(State stateType, boolean state){
if(state){
this.state |= stateType.value;
}else{
this.state &= ~stateType.value;
}
}
}

One way to check a value against a group of allowed values is a Set<Integer> that contains all the allowed values. You can construct such set in a static constructor of the class, i.e.
private static final Set<Integer> allowedState = new HashSet<Integer>();
static {
allowedState.add(STATE1);
allowedState.add(STATE2);
allowedState.add(STATE3);
}
Now you can check if the state passed to you is valid by verifying that allowedState contains stateType:
if (!allowedState.contains(stateType)) {
// Throw an exception
}
To ensure that the allowedState set is immutable use Collcetions.unmodifiableSet(). Modifier final only ensures that the reference cannot be redinded to another object.
However, an approach based on raw int constants is not idiomatic to Java. A better way to achieve the same effect would be wrapping the states in an enum (tutorial), which would make sure that only a valid constant could be passed to your setState method:
public enum State {
STATE1(0b1)
, STATE2(0b10)
, STATE3(0b100);
private final int bitMask;
State(int bitMask) { this.bitMask = bitMask; }
public int getBitMask() { return bitMask; }
}

Related

Can Java Enums shares some common codes among them?

I have two Enums as below
public enum Read {
PRIVATE (1), PUBLIC(2);
private final int value;
Read(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
And
public enum Write {
CREATE (1), UPDATE(2);
private final int value;
Write(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
Both enum needing some values to represent them. Is there a way for us to share the code, where the Read and Write "extends" from something that has value, instead of for every enum, I need to have getValue, value etc? Probably one way is to make a class, but thinking if we could make Enum "extensible"?
Don't fight it; embrace classes.
Enumerations generally represent some form of state; that is, each enum value has a specific business-associated state with it. You'd have to decide what Read.PRIVATE and Read.PUBLIC truly represented, but they're still states. The same is true of Write.CREATE and Write.UPDATE.
The real question now becomes, how do these two enums relate to one another? They likely don't, given that reading something is independent and severable from writing something.
In this instance, I'd probably represent it in a class:
public class Permission {
private Read readState;
private Write writeState;
public void setReadState(Read readState) {
this.readState = readState;
}
public void setWriteState(Write writeState) {
this.writeState = writeState;
}
}
It's unclear what the values would represent, since the enums are guaranteed unique, but take from this what you will.
You could use EnumSet to hold permissions like this:
Permission:
public enum Permission {
READ_PRIVATE, READ_PUBLIC, WRITE_CREATE, WRITE_UPDATE;
}
User:
public class User {
private final EnumSet<Permission> permissions;
public User(Permission... permissions) {
this.permissions = EnumSet.copyOf(Arrays.asList(permissions));
}
public boolean hasPermission(Permission permission) {
return permissions.contains(permission);
}
public void addPermisssion(Permission p) {
permissions.add(p);
}
public void removePermisssion(Permission p) {
permissions.remove(p);
}
}
Usage:
User user = new User(Permission.READ_PRIVATE, Permission.WRITE_UPDATE);
if ( user.hasPermission(Permission.WRITE_UPDATE) )
{
//do something...
}

Data type of variable size in Java?

In Java I want to create a data type, let's say Atom, which contains an index number, and when that index = 0, the Atom will contain a String datum, otherwise the Atom is just an index (Integer).
How can I do that?
I guess it would save some space if most Atoms are just indexes and only some contain Strings.
The following Factory Pattern illustrates how a static factory method createAtom creates instances of different classes (all Atom), with different data.
Here I made index final as changing it to 0, will not change the class of the object. Also Atom has to offer access to the optional datum.
public class Atom {
public final int index;
private Atom(int ix) {
this.index = ix;
}
public String getDatum() {
return null;
}
public static Atom createAtom(int index) {
return index != 0 ? new Atom(index) : new ExtendedAtom(index);
}
}
class ExtendedAtom extends Atom {
private String datum;
ExtendedAtom(int ix) {
super(ix);
}
#Override
public String getDatum() {
return datum;
}
}
There is no way to make a single class like that, because Java does not support "union" types. If you define a class with an int and a String, the space for both the int and the reference to a String would be allocated, defeating the space-saving purpose of what you are trying to achieve.
You could store your "atoms" as java.lang.Object values, but you would need to check their type and cast every time you need to obtain the index or the string. This approach is cumbersome, because primitive ints are wrapped in java.lang.Integer objects, adding to storage requirements.
A cleaner approach would be defining an interface for your Atom, and defining two classes, a StringAtom and an IntAtom, to store the two atom kinds in your program:
interface Atom {
boolean hasInt();
boolean hasString();
int getInt();
String getString();
}
class StringAtom implements Atom {
private final String s;
public StringAtom(String s) {this.s = s;}
boolean hasInt() {return false;}
boolean hasString() {return true;}
int getInt() {throw new IllegalStateException();}
String getString() {return s;}
}
class IntAtom implements Atom {
private final int n;
public IntAtom(int n) {this.b = b;}
boolean hasInt() {return true;}
boolean hasString() {return false;}
int getInt() {return n;}
String getString() {throw new IllegalStateException();}
}
Create a small class with an index member variable, a flag checking if that index is zero and a String datum that will be non-null only if the flag is true (indicating the index is zero).

Compilation error with ENUM class

sorry for asking such basic question. I am trying some hands on ENUM. below is my code. I am getting some compilation error . Any idea where is the problem. I want SAMPLEMAIL,BULKUSERS,ALLUSERS should be of integer type.
public enum EmailSendingOption {
SAMPLEMAIL, BULKUSERS, ALLUSERS;
private int emailSendingOptionType;
private EmailSendingOption(String optionType) {
int value = Integer.parseInt(optionType.trim());
emailSendingOptionType = value;
}
public int getEmailSendingOption() {
return emailSendingOptionType;
}
}
thanks.
You have defined a constructor but you haven't supplied arguments for each of your Enums.
Looks like your constructor should take an integer too. Saves having to parse a String each time. It's also safer.
e.g.
SAMPLEMAIL(10), etc.
With your constructor looking like:
private int emailSendingOptionType;
private EmailSendingOption(int optionType) {
this.emailSendingOptionType = optionType;
}
You need to make it like this:
public enum EmailSendingOption {
SAMPLEMAIL("1"), BULKUSERS("2"), ALLUSERS("3");
private int emailSendingOptionType;
private EmailSendingOption(String optionType) {
int value = Integer.parseInt(optionType.trim());
emailSendingOptionType = value;
}
public int getEmailSendingOption() {
return emailSendingOptionType;
}
}
enum are not integers in Java, they are objects. There is no sane reason you would pass an integer as a String to a constructor so it can be parsed into an integer. If you want an integer use an integer.
public enum EmailSendingOption {
SAMPLEMAIL(1), BULKUSERS(2), ALLUSERS(101);
private final int emailSendingOptionType;
private EmailSendingOption(int emailSendingOptionType) {
this.emailSendingOptionType = emailSendingOptionType;
}
public int getEmailSendingOption() {
return emailSendingOptionType;
}
}
Since you are providing a custom constructor to your Enum
EmailSendingOption(String optionType)
You need to add those parameter for each Enum constant.
Change it to:
public enum EmailSendingOption
{
SAMPLEMAIL("String"), BULKUSERS("String"), ALLUSERS("String");
...
}
You defined a constructor as needed a String as argument. SAMPLEMAIL this are a static object
of EmailSendingOption.

Better way to map from String constants to int constants in Java

I have a load of images of musical symbols which I need to do some processing on and for each one I need to get the integer code corresponding to its file name. There are 23 possible file name strings and 23 integer code and there are many images with the same name under different directories.
The solution I have so far is given (abbreviated) below. I have just defined a load of int and String constants and then written a method which is just a huge chain of if statements to do the translation.
What would be a better way to achieve the same effect? The way I've done it seems really awful! I thought about using some kind of Map, but I wasn't sure of the best way to do so.
public class Symbol {
public static final int TREBLE_CLEF = 0;
public static final int BASS_CLEF = 1;
public static final int SEMIBREVE = 2;
// ...
public static final String S_TREBLE_CLEF = "treble-clef";
public static final String S_BASS_CLEF = "bass-clef";
public static final String S_SEMIBREVE = "semibreve";
// ...
public static int stringCodeToIntCode(String strCode) {
if (strCode == S_TREBLE_CLEF) {
return TREBLE_CLEF;
} else if (strCode == S_BASS_CLEF) {
return BASS_CLEF;
} else if (strCode == S_SEMIBREVE) {
return SEMIBREVE;
} //...
else {
return -1;
}
}
}
I think you are looking for Enum where you can have String constant and its value.
Example:
public enum YourEnumClass{
STRING_CONST (5),
STRING_CONST2 (7),
.....
//constructor
//getValue() method
}
read linked tutorial for more details.
enum StringToInt{
TREBLE_CLEF(0),
......
}
Enum is the way to go.
Another example:
public enum Color {
WHITE(21), BLACK(22), RED(23), YELLOW(24), BLUE(25);
private int code;
private Color(int c) {
code = c;
}
public int getCode() {
return code;
}
how about a hashmap
HashMap<String,Integer> hm=new HashMap<String,Integer();
hm.put("treble-clef",0);
//rest
and get it by using this
int value=hm.get("treble-clef");

java - an enum question

I have encountered a weird problem in my app (java).
I have an enum. Something like that
public enum myEnum implement myIntrface{
valueA(1),valueb(2),valuec(3),valued(4)
private int i;
// and then - a constructor
public MyEnum(int number){
i = number;
}
private MyObj obj = new MyObj;
// getter and setter for obj
}
and in another class I have this
MyEnum.valueA.setObj(new Obj(...))
in briefe - I have an enum with a private instance member that has a set and a get.
So far so good -
The only thing that amazes me is that later on I look at the value of the MyEnum.valueA().obj is null.
there is nothing that updates the value to null, I have even gave it a default value in the constructor and I still see it null later.
any suggestions?
Enums should be un-modifiable classes so you shouldn't really be doing this. If your looking to modify the state of a type based object like an enum you should use an final class approach with embedded constants. Below is an example of a class based approach with a modifiable name an a un-modifiable name...
public final class Connection {
public static final Connection EMAIL = new Connection("email");
public static final Connection PHONE = new Connection("phone");
public static final Connection FAX = new Connection("fax");
/**/
private final String unmodifiableName; //<-- it's final
private String modifiableName;
/*
* The constructor is private so no new connections can be created outside.
*/
private Connection(String name) {
this.unmodifiableName = name;
}
public String getUnmodifiableName() {
return unmodifiableName;
}
public String getModifiableName() {
return modifiableName;
}
public void setModifiableName(String modifiableName) {
this.modifiableName = modifiableName;
}
}
The purpose of enums is to represent constant values. It does not make any sense to set the fields of a constant value.
You should declare your fields as final, and use the constructor to initialize all of them.
For reference, the following code works as expected:
public class Test {
public static enum MyEnum {
valueA(1),valueb(2),valuec(3),valued(4);
private int i;
private Object o;
private MyEnum(int number) {
i = number;
}
public void set(Object o) {
this.o = o;
}
public Object get() {
return o;
}
}
public static void main(String[] args) {
System.out.println(MyEnum.valueA.get()); // prints "null"
MyEnum.valueA.set(new Integer(42));
System.out.println(MyEnum.valueA.get()); // prints "42"
}
}
the cause of this problem is the db40 framework . It loads an enum from the db using reflection. This is well documented .
http://developer.db4o.com/Forums/tabid/98/aft/5439/Default.aspx

Categories