I want to create an enum and declare several constants inside of it for inner usage...
public enum SearchType {
static final String TEXT = "text";
static final String BOOLEAN = "boolean";
STARTS_WITH(TEXT),
ENDS_WITH(TEXT),
CONTAINS(BOOLEAN),
WILDCARD(TEXT),
REGEXP(TEXT),
RANGE(TEXT)
private String searchType;
private SearchType(String type) {
searchType = type;
}
}
unfortunately it can't be done this way. Best solution I've come up with so far is to declare a nested interface to store constants...
public enum SearchType {
STARTS_WITH(Categories.TEXT),
ENDS_WITH(Categories.TEXT),
CONTAINS(Categories.BOOLEAN),
WILDCARD(Categories.TEXT),
REGEXP(Categories.TEXT),
RANGE(Categories.TEXT)
interface Categories{
static final String TEXT = "text";
static final String BOOLEAN = "boolean";
}
private String searchType;
private SearchType(String type) {
searchType = type;
}
}
so I'm wondering if there is a better way to do so?
I would use an enum for the Categories as well. If you place this in a top level class, it will look natural.
You have to define your enum values before any other constants.
AFAIK This is done to simplify the syntax. You have the enum values first with a special, simplified syntax, followed by the constants you define. The need for this is more obvious when you start overriding methods in your constants.
Related
I must define a class which all it does is hold constants.
public static final String CODE1 = "100";
public static final String CODE2 = "200";
Now I want use these values in other classes. Is it better to use this class as a static class or instantiate it ?
Thanks.
Note : I know enums but in this context, I must use a class.
Just to use the values, you certainly shouldn't instantiate the class. Just because you can access static members as if they were instance members doesn't mean it's a good idea.
If the class really only contains constants - and if you're sure that's a good idea, rather than those constants appearing within classes which are directly related to them - you should make it a final class with a private constructor, so that no-one can pointlessly instantiate it:
public final class Codes {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
// Prevent instantiation
private Codes() {
}
}
Don's answer suggesting using an enum is a very good idea too - it means you can use Code in your API everywhere that you don't need the exact string representation, which prevents you from accidentally using non-code values.
Jons answer is correct, although I want to show you a solution with an enum.
There is a disadvantage in accessing its String value as you have to call Code.CODE1.text() instead of Code.CODE1.
public enum Code {
CODE1("100"), CODE2("200");
private String text;
Codes(String text) {
this.text = text;
}
public String text() {
return text;
}
}
java language spec and JVM spec allow you to do anything you wanted, whether instantiate a class or use final or use other way....
Just use Eclipse and try !
while there is some good practice, Jon Skeet's answer is one good practice.
Java Language is not support global variable
public class ComonFun {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
public static String CODE1(){
return CODE1;
}
public static String CODE2(){
return CODE2;
}
}
implement
public class Main {
public static void main(String[] args) {
System.out.println(ComonFun.CODE1());
System.out.println(ComonFun.CODE2());
}
}
i think that you need simply to declare an interface, you won't need to specify the clause "public static final". and it can be usuable throgh the hall project.
Use them as static, don't go for instantiation.
Even use static import as a benefit.
package coma;
import static coma.ImportStatments.*;
public class UsingClass {
public static void main(String[] args) {
System.out.println(CODE1);
}
}
And the class with final variables would look like this:
package coma;
public class ImportStatments {
public static final String CODE1 = "100";
public static final String CODE2 = "200";
}
Check this example:
public interface IConstants {
public enum Levels {
LOW("30 points"), MEDIUM("50 points")
};
public enum Cars {
PORSCHE("250 km/h"), FORD("180 km/h")
}
}
I'd like to have an interface like this, because I want to access my enums this way:
String level = IConstants.Levels.MEDIUM;
String car = IConstants.Cars.PORSCHE;
The compiler shows this message:
constructor IConstants."enum name" is undefined.
Solved this way :
public class Constants {
public static class Levels {
public static String LOW = "30 points";
public static String MEDIUM = "50 points";
};
//... other classes
}
-useful for me in (my case) to have a "tree" in my constants, every constant starting by keyword Constants then subcategory and then value -> Constants.Levels.LOW.
//critize it if it's very bad practise, i agree all comments
-another maybe good thing that there will be all constants in one class
Like Boris the spider told you in comment declaring constants in interfaces is an anti pattern. However your problem comes from the fact that you are passing a String to any instance of your enum but you are not declaring a constructor for this
public enum Levels {
LOW("30 points"), MEDIUM("50 points")
private final String pts;
private Levels(String pts) {
this.pts = pts;
}
public String getPoints() {
return pts;
}
};
This should work.
You are missing constructors in both enums. A private variable and the constructor is required, e.g.
public enum Levels {
private String name;
public Levels(String name) {
this.name = name;
}
}
Also it is considered bad practice to put inner classes, constants in interfaces.
To add to other answers, it will still not compile after an enum constructor is added, because you are assigning a String variable to a Levels or Cars. Please use:
String level = IConstants.Levels.MEDIUM.methodToAccessString();
String car = IConstants.Cars.PORSCHE.methodToAccessString();
Replacing methodToAccessString() with whatever you call it, of course.
I'm unable to use an Enum taken from a Constant as a parameter in an annotation. I get this compilation error: "The value for annotation attribute [attribute] must be an enum constant expression".
This is a simplified version of the code for the Enum:
public enum MyEnum {
APPLE, ORANGE
}
For the Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD })
public #interface MyAnnotation {
String theString();
int theInt();
MyEnum theEnum();
}
And the class:
public class Sample {
public static final String STRING_CONSTANT = "hello";
public static final int INT_CONSTANT = 1;
public static final MyEnum MYENUM_CONSTANT = MyEnum.APPLE;
#MyAnnotation(theEnum = MyEnum.APPLE, theInt = 1, theString = "hello")
public void methodA() {
}
#MyAnnotation(theEnum = MYENUM_CONSTANT, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
public void methodB() {
}
}
The error shows up only in "theEnum = MYENUM_CONSTANT" over methodB. String and int constants are ok with the compiler, the Enum constant is not, even though it's the exact same value as the one over methodA. Looks to me like this is a missing feature in the compiler, because all three are obviously constants. There are no method calls, no strange use of classes, etc.
What I want to achieve is:
To use the MYENUM_CONSTANT in both the annotation and later in the code.
To stay type safe.
Any way to achieve these goals would be fine.
Edit:
Thanks all. As you say, it cannot be done. The JLS should be updated. I decided to forget about enums in annotations this time, and use regular int constants. As long as the int is assigned from a named constant, the values are bounded and it's "sort of" type safe.
It looks like this:
public interface MyEnumSimulation {
public static final int APPLE = 0;
public static final int ORANGE = 1;
}
...
public static final int MYENUMSIMUL_CONSTANT = MyEnumSimulation.APPLE;
...
#MyAnnotation(theEnumSimulation = MYENUMSIMUL_CONSTANT, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
public void methodB() {
...
And I can use MYENUMSIMUL_CONSTANT anywhere else in the code.
"All problems in computer science can be solved by another level of indirection" --- David Wheeler
Here it is:
Enum class:
public enum Gender {
MALE(Constants.MALE_VALUE), FEMALE(Constants.FEMALE_VALUE);
Gender(String genderString) {
}
public static class Constants {
public static final String MALE_VALUE = "MALE";
public static final String FEMALE_VALUE = "FEMALE";
}
}
Person class:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
#JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = Person.GENDER)
#JsonSubTypes({
#JsonSubTypes.Type(value = Woman.class, name = Gender.Constants.FEMALE_VALUE),
#JsonSubTypes.Type(value = Man.class, name = Gender.Constants.MALE_VALUE)
})
public abstract class Person {
...
}
I think that the most voted answer is incomplete, since it does not guarantee at all that the enum value is coupled with the underlying constant String value. With that solution, one should just decouple the two classes.
Instead, I rather suggest to strengthen the coupling shown in that answer by enforcing the correlation between the enum name and the constant value as follows:
public enum Gender {
MALE(Constants.MALE_VALUE), FEMALE(Constants.FEMALE_VALUE);
Gender(String genderString) {
if(!genderString.equals(this.name()))
throw new IllegalArgumentException();
}
public static class Constants {
public static final String MALE_VALUE = "MALE";
public static final String FEMALE_VALUE = "FEMALE";
}
}
As pointed out by #GhostCat in a comment, proper unit tests must be put in place to ensure the coupling.
It seems to be defined in the JLS #9.7.1:
[...] The type of V is assignment compatible (§5.2) with T, and furthermore:
[...]
If T is an enum type, and V is an enum constant.
And an enum constant is defined as the actual enum constant (JLS #8.9.1), not a variable that points to that constant.
Bottom line: if you want to use an enum as a parameter for your annotation, you will need to give it an explicit MyEnum.XXXX value. If you want to use a variable, you will need to pick another type (not an enum).
One possible workaround is to use a String or int that you can then map to your enum - you will loose the type safety but the errors can be spotted easily at runtime (= during tests).
The controlling rule seems to be "If T is an enum type, and V is an enum constant.", 9.7.1. Normal Annotations. From the text, it appears the JLS is aiming for extremely simple evaluation of the expressions in annotations. An enum constant is specifically the identifier used inside the enum declaration.
Even in other contexts, a final initialized with an enum constant does not seem to be a constant expression. 4.12.4. final Variables says "A variable of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28), is called a constant variable.", but does not include a final of enum type initialized with an enum constant.
I also tested a simple case in which it matters whether an expression is a constant expression - an if surrounding an assignment to an unassigned variable. The variable did not become assigned. An alternative version of the same code that tested a final int instead did make the variable definitely assigned:
public class Bad {
public static final MyEnum x = MyEnum.AAA;
public static final int z = 3;
public static void main(String[] args) {
int y;
if(x == MyEnum.AAA) {
y = 3;
}
// if(z == 3) {
// y = 3;
// }
System.out.println(y);
}
enum MyEnum {
AAA, BBB, CCC
}
}
I quote from the last line in the question
Any way to achieve these goals would be fine.
So i tried this
Added a enumType parameter to the annotation as a placeholder
#Retention(RetentionPolicy.RUNTIME)
#Target({ ElementType.METHOD })
public #interface MyAnnotation {
String theString();
int theInt();
MyAnnotationEnum theEnum() default MyAnnotationEnum.APPLE;
int theEnumType() default 1;
}
Added a getType method in the implementation
public enum MyAnnotationEnum {
APPLE(1), ORANGE(2);
public final int type;
private MyAnnotationEnum(int type) {
this.type = type;
}
public final int getType() {
return type;
}
public static MyAnnotationEnum getType(int type) {
if (type == APPLE.getType()) {
return APPLE;
} else if (type == ORANGE.getType()) {
return ORANGE;
}
return APPLE;
}
}
Made a change to use an int constant instead of the enum
public class MySample {
public static final String STRING_CONSTANT = "hello";
public static final int INT_CONSTANT = 1;
public static final int MYENUM_TYPE = 1;//MyAnnotationEnum.APPLE.type;
public static final MyAnnotationEnum MYENUM_CONSTANT = MyAnnotationEnum.getType(MYENUM_TYPE);
#MyAnnotation(theEnum = MyAnnotationEnum.APPLE, theInt = 1, theString = "hello")
public void methodA() {
}
#MyAnnotation(theEnumType = MYENUM_TYPE, theInt = INT_CONSTANT, theString = STRING_CONSTANT)
public void methodB() {
}
}
I derive the MYENUM constant from MYENUM_TYPE int, so if you change MYENUM you just need to change the int value to the corresponding enum type value.
Its not the most elegant solution, But i'm giving it because of the last line in the question.
Any way to achieve these goals would be fine.
Just a side note, if you try using
public static final int MYENUM_TYPE = MyAnnotationEnum.APPLE.type;
The compiler says at the annotation- MyAnnotation.theEnumType must be a constant
My solution was
public enum MyEnum {
FOO,
BAR;
// element value must be a constant expression
// so we needs this hack in order to use enums as
// annotation values
public static final String _FOO = FOO.name();
public static final String _BAR = BAR.name();
}
I thought this was the cleanest way. This meets couple of requirements:
If you want the enums to be numeric
If you want the enums to be of some other type
Compiler notifies you if a refactor references a different value
Cleanest use-case (minus one character): #Annotation(foo = MyEnum._FOO)
EDIT
This leads occasionally to compilation error, which leads to the reason of the original element value must be a constant expression
So this is apparently not an option!
I am designing a text-only videogame with two characters not often seen together, yet very much alike in heart and disposition.
My problem is that I don't know how to initialise an enum constant through a constructor using a static final inner constant. Otherwise the game is good to go. ;)
Here's the dilemma:
The enum constants must be defined in the first line of the enum, if I am not mistaken
The first line can't refer to anything coming after it (i.e. "cannot reference a field before it is defined")
How do I resolve this catch-22?
Here some sample code released from the game under non-disclosure agreement:
enum ValiantHeroWithPrincessSavingTendencies {
SUPERMARIO(TYPICAL_QUOTE_FROM_MARIO), ZELDA(TYPICAL_QUOTE_FROM_ZELDA);
private String aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
public String getQuoteUnderStressfulCircumstances() {
return aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
}
private ValiantHeroWithPrincessSavingTendencies(String quote) {
aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive = quote;
}
private static final String TYPICAL_QUOTE_FROM_ZELDA = "Have at ya!";
private static final String TYPICAL_QUOTE_FROM_MARIO = "We, wagliu'!";
}
I am trying to initialise SUPERMARIO using TYPICAL_QUOTE_FROM_MARIO but I haven't defined TYPICAL_QUOTE_FROM_MARIO yet. Moving the private static final field before SUPERMARIO is illegal, I think.
The only viable options are to either a) move your constants to another class or b) just put your constants directly into the value initializers.
If you move your constants, you can make the class a static class in the enum:
enum ValiantHeroWithPrincessSavingTendencies {
SUPERMARIO(Quotes.TYPICAL_QUOTE_FROM_MARIO),
ZELDA(Quotes.TYPICAL_QUOTE_FROM_ZELDA);
private String aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
public String getQuoteUnderStressfulCircumstances() {
return aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive;
}
private ValiantHeroWithPrincessSavingTendencies(String quote) {
aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive = quote;
}
private static class Quotes {
private static final String TYPICAL_QUOTE_FROM_ZELDA = "Have at ya!";
private static final String TYPICAL_QUOTE_FROM_MARIO = "We, wagliu'!";
}
}
You can just access them via class name:
enum ValiantHeroWithPrincessSavingTendencies {
SUPERMARIO(ValiantHeroWithPrincessSavingTendencies.TYPICAL_QUOTE_FROM_MARIO),
ZELDA(ValiantHeroWithPrincessSavingTendencies.TYPICAL_QUOTE_FROM_ZELDA);
...
private static final String TYPICAL_QUOTE_FROM_ZELDA = "Have at ya!";
private static final String TYPICAL_QUOTE_FROM_MARIO = "We, wagliu'!";
}
It's simplier than Brian's solution
The private static final constants are local to the enum; just code them in the instance definitions. After that point they can be accessed internally from the aPreparedQuotePurportedToBeSpontaneousAlmostImpulsive variable.
You could always do something hacky like this:
public enum Derp
{
SOMETHING(),
SOMETHINGELSE();
private String herp;
public static final String A = "derp", B = "derp2";
public String getHerp()
{
return herp;
}
static
{
SOMETHING.herp = A;
SOMETHINGELSE.herp = B;
}
}
I have following fields
a(String)
b(String)
c(String)
d(boolean)
e(boolean)
Is it possible to have them all in an Enum like following?
public enum Fields {
a("A")
b("B")
c("C")
d(true)
e(false)
}
You can have them but you should define constructors which takes String or boolean as parameters.
public enum Constants {
CONSTANT_STRING1("CONSTANT_VALUE1"),
CONSTANT_STRING2("CONSTANT_VALUE2"),
CONSTANT_STRING3("CONSTANT_VALUE3");
CONSTANT_FLAG1(false);
CONSTANT_FLAG2(true);
private String constants;
private boolean flag;
private Constants(String cons) {
this.constants = cons;
}
private Constants(boolean lFlag) {
this.flag= lFlag;
}
}
It sounds like you are using an enum to store constants, which is bad practice.
It is possible, but I would advice against it. In most cases, what you really want is a common interface, which is implemented by two (or more) different classes.
Please also note that is fully legitimate for an enum to implement an interface, but it is seldom you see two enums implement the same interface like in the example below:
public interface Fields {
}
public enum StringFields implements Fields {
A("A"),
B("B"),
C("C")
private StringFields(String str) {
this.str = str;
}
private final String str;
}
public enum BooleanFields implements Fields {
D(true),
E(false);
private BooleanFields(boolean val) {
this.val = val;
}
private final boolean val;
}
You can have two different constructors in the enum, but that means you need to have two fields (with one of them not being set). I do not think this would make much sense.
public enum Fields {
a("A"), b("B"), c("C"), d(true), e(false);
Fields(String str) {
strval = str;
value = false;
}
Fields(boolean val) {
strval = null;
value = val;
}
private final String strval;
private final boolean value;
}
EDITED*** Compiles now. You have to initialize both at the same time.