I have an interface where I have defined constants used across application. I have a scenario where I need to initialize constants based on condition.
for eg , something like,
if(condition){
public static final test = "some value";
}
Is this possible.
Interfaces are to be implemented. They should not be used as carriers for constants. If you need such a thing you might consider a final class with a private constructor.
What you seem to want is a global variable or singleton, which are rather problematic designs, or something like a c preprocessor directive, dynamically evaluated at compile time.
So consider if it is really a constant you need - something which is defined at compile (or class loading) time.
Interface contains no code.
Split your interface in many specific interfaces declaring and initializing their own constants.
This will follow the Interface Segregation Principle where a class doesn't have to be bored by some useless constants or methods.
Of course, Java let classes implement several interfaces at once. So if you have specific interfaces to mix up for one concrete class, this would be pretty easy.
You can set static final variable with condition in following way:
public class Test {
public static final String test;
static {
String tmp = null;
if (condition) {
tmp = "ss";
}
test = tmp;
}
}
You can do it in one line, also in interface with:
public static final String test = condition ? "value" : "other value";
This can be another reason why Interface constants are bad. You can simply use enums Like below.
public enum Const {
SAMPLE_1(10), SAMPLE_2(10, 20);
private int value1, value2;
private Const(int value1, int value2) {
this.value1 = value1;
this.value2 = value2;
}
private Const(int value1) {
this.value1 = value1;
}
//Value based on condition
public int getValue(boolean condition) {
return condition == true ? value2 : value1;
}
//value which is not based on conditions
public int getValue() {
return value1;
}
}
public interface InitializeInInterface {
public static final String test = Initializer.init();
static class Initializer {
public static String init() {
String result = "default value";
InputStream is = InitializeInInterface.class.getClassLoader().getResourceAsStream("config.properties");
Properties properties = new Properties();
try {
properties.load(is);
} catch (IOException e) {
e.printStackTrace();
}
if ("bar".equals(properties.getProperty("foo"))) {
result = "some value";
}
return result;
}
}
}
Related
I need to pass a class variable to an enum while initializing it .But the class variable is not accessible while initializing the enum . So how can this be achieved ?
I tried passing variable of another class, same class where the enum resides . Both didn't work.
public class ComponentConstants {
public Constants constants = Constants.getInstance();
enum FIELDS_RESOURCES {
//instead of text i want to use constants.data_type.text. But I was not able to.
SourcetType(true, "text", "Source Type", "source_type", 255, false); //No I18N
private VOCFIELDS_RESOURCES(boolean isCustomField, String data_type, String field_label, String api_name, int length, boolean isVisible) {
this.isCustomField = isCustomField;
this.data_type = data_type;
this.field_label = field_label;
this.api_name = api_name;
this.length = length;
this.isVisible = isVisible;
}
}
}
In the above I want to use the value from constants since if there is any change there ,it should be reflected in my code too . Single point of constants , but i was not able to use it. How can this be achieved and why is it not allowing to use other variables? Thanks!
public class Main {
public enum Enumeration {
Test(Constants.a, Constants.b); // can refer to constant "a" & "b" static variables
private final String a;
private final String b;
Enumeration(String a, String b) {
this.a = a;
this.b = b;
}
}
public static class Constants {
static String a = "a";
static String b = "b";
}
}
If you utilize static fields as constants, they can be referenced within enumeration constructors. More details here regarding enum fields.
I am refactoring some old code and find a class "Tags" containing string constants, most of them tags used by some XML-Parser-Handlers. But also for serialising data. They are defined blank:
public static String PROXY, NAME, X, Y, KEY, ... CODES;
and initialized by their own name:
static {
Field[] fields = Tags.class.getFields();
for (int i = 0; i < fields.length; ++i) {
try {
// init field by its lowercased name
String value = fields[i].getName().toLowerCase();
fields[i].set(null, value);
} catch (Exception e) {
// exception should not occur, because only strings over here.
e.printStackTrace();
}
}
}
Does it make sense in your opinion?
Pros:
all tags in one place
guaranteed correspondence between name & value (no mistyping)
support by IDE autocompletion when typing
Cons:
not really constants (not final)
readability -- to just use the string literals "proxy", "name" etc. would be more straightforward
the initialisation by reflection consumes processing time -- delays startup time
So -- keep it or refactor it?
You can replace these constants by an enum and still keep the advantages you've listed:
public enum Tags {
PROXY("proxy"),
NAME("name"),
X("x"),
Y("y");
public final String value;
private Tags(String value) {
this.value = value;
if (!value.equals(name().toLowerCase())) {
throw new RuntimeException("Value and name do not match");
}
}
public static void main(String[] args) {
for (Tags tag : Tags.values()) {
System.out.println(tag + "\t" + tag.value);
}
}
}
In the code above, the test value.equals(name().toLowerCase()) is not necessary but you seem concerned about mistyping errors
Try this:
enum Enum {
PROXY, NAME, X, Y;
public String toString() {
return name().toLowerCase();
}
}
or this:
public enum Tags {
proxy, name, x, y
}
I have an annotation I can't change which expects two String arguments.
I'd like to use it like this:
#RequestMapping( MyUrls.FOO.a, MyUrls.FOO.b )
This is how I imagined implementing it
public enum MyUrls {
FOO("a", "b"),
BAR("c", "d");
public String a, b;
MyUrls(String a, String b) {
this.a = a;
this.b = b;
}
}
This doesn't work since a or b can't be statically resolved.
What alternatives do I have which are nicer than:
class MyUrls {
public static String FOO_A = "";
public static String FOO_B = "";
// ...
}
Although your question does not look like a question but as a declaration, I agree with you.
You cannot use enum members when you are defining annotations. Only "real" constants, i.e. static final fields and constant expressions are applicable. So, there is no good alternative right now.
You could use a static inner class to group your strings.
class MyUrls {
public static final class Foo{
public static final String A = "";
public static final String B = "";
// ...
}
}
//works as
MyUrls.Foo.A
in an interface, I store constants in this way (I'd like to know what you think of this practice). This is just a dummy example.
interface HttpConstants {
/** 2XX: generally "OK" */
public static final int HTTP_OK = 200;
public static final int HTTP_CREATED = 201;
public static final int HTTP_ACCEPTED = 202;
public static final int HTTP_NOT_AUTHORITATIVE = 203;
public static final int HTTP_NO_CONTENT = 204;
public static final int HTTP_RESET = 205;
public static final int HTTP_PARTIAL = 206;
...
}
Is there a way I can iterate over all constants declared in this interface ?
Using reflection:
Field[] interfaceFields=HttpConstants.class.getFields();
for(Field f:interfaceFields) {
//do something
}
But anyway, if you can redesign your class, I would recomend you to handle a static enum constants construction. So, suposing your class will contain always an int value for every constant:
enum HttpConstants {
HTTP_OK(200), HTTP_CREATED(201), HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),HTTP_NO_CONTENT(204),
HTTP_RESET(205), HTTP_PARTIAL(206) /* ... */;
private int value;
HttpConstants(int aValue) {
value=aValue;
}
public int getValue() {
return value;
}
}
Then, to loop on it:
for(HttpConstants val: HttpConstants.values()) {
int value=val.getValue();
//...
}
Thus, avoiding the access to the reflection API.
I would create these constants as an enumeration. Enums in Java can have their own fields and methods, which very convenient for your case. So I would do this the following way:
enum HttpConstant {
HTTP_OK(200),
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private final int id;
HttpConstant(int id) {
this.id = id;
}
int getId() {
return id;
}
}
Now the iteration is easy:
for (HttpConstant constant : HttpConstant.values()) {
//Do something with the constant
}
This way it is also easy to add associate some new values with the constants, you just have to add new fields.
Right now you may use reflection:
Field[] interfaceFields = HttpConstants.class.getFields();
for (Field field : interfaceFields) {
int constant = field.getInt(null);
//Do something with the field
}
However, it is better to use the approach with enums because with reflection coding errors result in runtime exceptions instead of compile-time errors.
for(Field f : HttpConstants.class.getFields()){
int constant = f.getInt(null);
}
public enum HttpConstant {
/** 2XX: generally "OK" */
HTTP_OK(200).
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private int code;
private HttpConstant(int code) {
this.code = code;
}
public int getCode() {
return code;
}
}
with HttpConstant.values().
Well usually when i have something like that i make a Map in the interface that has the keys - constant names with values constant - values.
And that's how i can iterate over them.
I'd like to know what you think of this practice
Consider using an enum instead of an interface with constants.
enum HttpResultCode {
HTTP_OK(200),
HTTP_CREATED(201),
HTTP_ACCEPTED(202),
HTTP_NOT_AUTHORITATIVE(203),
HTTP_NO_CONTENT(204),
HTTP_RESET(205),
HTTP_PARTIAL(206);
private final int code;
private HttpResultCode(int code) {
this.code = code;
}
public int getCode(int code) {
return code;
}
public static HttpResultCode forCode(int code) {
for (HttpResultCode e : HttpResultCode.values()) {
if (e.code == code) {
return e;
}
}
throw new IllegalArgumentException("Invalid code: " + code);
}
}
I need to use an Enum with a combobox (values shown below).
YES (shown as YES on UI, stored in DB as Y)
NO (shown as NO on UI, stored in DB as N)
DEFAULT (shown as "" on UI, stored in DB as null)
The Enum has methods to perform the following -
toString() - to provide the custom String for UI. (showing the combo options)
OptionToDB (static) - Convert a selected option to db value (on save / update)
DBToOption (static)- Convert a DB value to selcted option (while loading the screen)
static enum EnumOption{
YES,NO,DEFAULT;
....
public static EnumOption DBToOption(String val){
if("Y".equals(val)){
return YES;
} else if("N".equals(val)){
return NO;
}else {
return DEFAULT;
}
}
....
}
It works pretty well, but the issue with above methods is that it uses if/else comparison to deduce which option / db value to be returned.
I thought of storing the dbValue as a field in enum but I was not able to reduce the if/else from DBToOption.
Can this if/else be avoided in any way using a better design??
If you store the dbValue as a field in the enum, you can remove the if/else and replace it with a for-loop, although I don't see anything wrong with those if/elses for this particular case:
static enum EnumOption {
YES("Y"),
NO("N"),
DEFAULT("");
private final String value;
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
for (EnumOption opt : EnumOption.values()) {
if (opt.value.equals(val)) {
return opt;
}
}
return DEFAULT;
}
}
public enum EnumOption {
YES("Y"), NO("N"), DEFAULT("");
private final String value;
private final static Map<String, EnumOption> options;
static {
options = new HashMap<String, EnumOption>();
for (EnumOption opt : EnumOption.values()) {
options.put(opt.value, opt);
}
}
private EnumOption(String value) {
this.value = value;
}
public static EnumOption DBToOption(String val) {
return options.get(val) != null ? options.get(val) : DEFAULT;
}
}
And here is the test that proves it works.
public void testDBToOption() {
assertEquals(EnumOption.NO, EnumOption.DBToOption("N"));
assertEquals(EnumOption.YES, EnumOption.DBToOption("Y"));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(""));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption(null));
assertEquals(EnumOption.DEFAULT, EnumOption.DBToOption("R"));
}
So you want to get rid of the remaining if/else ...Are you doing Object Calisthenics?
You could do the following, if you do not have compatibility issues:
public enum EnumOption {
Y("Y", "YES"),
N("N", "NO"),
D("D", "");
private final String dbValue;
private final String uiValue;
private EnumOption(String dbValue, String uiValue) {
this.dbValue = dbValue;
this.uiValue = uiValue;
}
public String getDbValue() {
return this.dbValue;
}
public String uiValue() {
return this.uiValue;
}
public static EnumOption getFromDb(String dbValue) {
return EnumOption.valueOf(dbValue);
}
}
Since each enum value can only occur once, this has at least the same performance as all the other implementations.
For details about the automatically generated valueOf(String) method in enum types, and James DW's solution, you can read up in Josh Bloch's Effective Java Item 30 (Use enums instead of int constants), page 154.