I want to refactor old code that uses a class of constants to enum, the code is already being used in a several places inside the code.(I know it's possible in eclipse, but haven't found it on IntelliJ Refactoring Dialogs)
Current State:
public class MyConstants {
public static String MY_CONSTANT_1 = "MY_CONSTANT_1_VALUE";
public static String MY_CONSTANT_2 = "MY_CONSTANT_2_VALUE";
public static String MY_CONSTANT_3 = "MY_CONSTANT_3_VALUE";
}
public class MyClass {
//usage of constant
if (mString.equals(MyConstants.MY_CONSTANT_1)){}
}
Expected result:
enum MyEnum {
MY_CONSTANT_1("MY_CONSTANT_1_VALUE"),MY_CONSTANT_2("MY_CONSTANT_2_VALUE"),MY_CONSTANT_3("MY_CONSTANT_3_VALUE")
private final String value;
MyEnum(String aValue){
value = aValue;
}
public String getValue(){
return value;
}
}
public class MyClass {
//usage of constant
if (mString.equals(MyConstants.MY_CONSTANT_1.getValue())){}
}
Note: I know Android official documentation recommend not to use enum but this is not my question.
You can't do it with Android Studio automatically.
Related
I want to create a method, that:
Takes the type of an enum and a String as arguments
The String is the name of one specific enum instance
Returns the enum instance that fits that name.
What I have tried:
In class TestUtil.java:
public static <E extends Enum<E>> E mapToEnum(Enum<E> mappingEnum, String data) {
return mappingEnum.valueOf(E, data); // Not working, needs Class of Enum and String value
}
The enum:
public enum TestEnum {
TEST1("A"),
TEST2("B");
private String value;
private TestEnum(String value) {
this.value = value;
}
}
How it should work (For example in main method):
TestEnum x = TestUtil.mapToEnum(TestEnum.class, "TEST1"); // TEST1 is the name of the first enum instance
The problem is, that I can't figure out what I need to pass into the mapToEnum method, so that I can get the valueOf from that Enum.
If the code you provided is acceptable:
public static <E extends Enum<E>> E mapToEnum(Enum<E> mappingEnum, String data) {
return mappingEnum.valueOf(E, data); // Not working, needs Class of Enum and String value
}
Then all you have to do is fix it.
Here's the code I tested:
static <T extends Enum<T>> T mapToEnum(Class<T> mappingEnum, String data) {
return Enum.valueOf(mappingEnum, data);
}
Usage:
#Test
public void test() {
TestEnum myEnum = mapToEnum(TestEnum.class, "TEST1");
System.out.println(myEnum.value); //prints "A"
}
Strongly suggest using Apache commons-lang library for boiler plate function like this ...
TestEnum x = EnumUtils.getEnum(TestEnum.class, "TEST1");
... which is exactly the code #Fenio demonstrates but handles null or wrong input with a null instead of throwing an Exception.
If you didn't know about this then check out what the rest of the lang3 library holds. I view it as a de-facto standard, saving millions of devs from re-writing minor plumbing utilities.
This is how you can iterate the enum class value and match with the parameter you have passed in the method, please check the below-mentioned code.
enum TestEnum {
TEST1("test1"),
TEST2("test2");
private String value;
private TestEnum(String value) {
this.value = value;
}
public String getName() {
return value;
}
public static TestEnum mapToEnum(String data) {
for (TestEnum userType : TestEnum.values()) {
if (userType.getName().equals(data)) {
return userType;
}
}
return null;
}
}
I wonder if there are another ways to find attributes in specific class are non-referenced by other classes (I mean, non used attributes).
My way is like that, for example I have a class like:
public class EABHeaderInformation implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4986763088497593972L;
//BargainFinder - AlternateBooking
private int multiTicketSequencdNmbr;
private String resBookDesigCode;
private LocalDateTime departureDate;
private LocalDateTime lastTicketingDate;
private List<String> text;
private String validatingCarrierCode;
public String getValidatingCarrierCode() {
return validatingCarrierCode;
}
public void setValidatingCarrierCode(String validatingCarrierCode) {
this.validatingCarrierCode = validatingCarrierCode;
}
public int getMultiTicketSequencdNmbr() {
return multiTicketSequencdNmbr;
}
public void setMultiTicketSequencdNmbr(int multiTicketSequencdNmbr) {
this.multiTicketSequencdNmbr = multiTicketSequencdNmbr;
}
public String getResBookDesigCode() {
return resBookDesigCode;
}
public void setResBookDesigCode(String resBookDesigCode) {
this.resBookDesigCode = resBookDesigCode;
}
public LocalDateTime getDepartureDate() {
return departureDate;
}
public void setDepartureDate(LocalDateTime departureDate) {
this.departureDate = departureDate;
}
public LocalDateTime getLastTicketingDate() {
return lastTicketingDate;
}
public void setLastTicketingDate(LocalDateTime lastTicketingDate) {
this.lastTicketingDate = lastTicketingDate;
}
public List<String> getText() {
return text;
}
public void setText(List<String> text) {
this.text = text;
}}
It's a simple POJO with getter and setters. I check every getter and setter with 'Open Call Hierarchy' in Eclipse, to find out if the attribute is used by others or not. But it takes a lot of time when I work on bigger classes than this.
So, is there a faster way to do this? Thanks for replies.
Eclipse can already create a warning or error for unused private members, but for public ones the Eclipse stance has always been that it's not a valuable feature. I tend to disagree, because many users have a limited scope that would be useful (specifically, all, or a subset of, the projects in the workspace). See this feature request, this one, and this one.
There are some third party options, such as UCDetector and this simple plug-in example.
See also this SO question and the answers.
I'm writing a library, which has a predefined set of values for an enum.
Let say, my enum looks as below.
public enum EnumClass {
FIRST("first"),
SECOND("second"),
THIRD("third");
private String httpMethodType;
}
Now the client, who is using this library may need to add few more values. Let say, the client needs to add CUSTOM_FIRST and CUSTOM_SECOND. This is not overwriting any existing values, but makes the enum having 5 values.
After this, I should be able to use something like <? extends EnumClass> to have 5 constant possibilities.
What would be the best approach to achieve this?
You cannot have an enum extend another enum, and you cannot "add" values to an existing enum through inheritance.
However, enums can implement interfaces.
What I would do is have the original enum implement a marker interface (i.e. no method declarations), then your client could create their own enum implementing the same interface.
Then your enum values would be referred to by their common interface.
In order to strenghten the requirements, you could have your interface declare relevant methods, e.g. in your case, something in the lines of public String getHTTPMethodType();.
That would force implementing enums to provide an implementation for that method.
This setting coupled with adequate API documentation should help adding functionality in a relatively controlled way.
Self-contained example (don't mind the lazy names here)
package test;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<HTTPMethodConvertible> blah = new ArrayList<>();
blah.add(LibraryEnum.FIRST);
blah.add(ClientEnum.BLABLABLA);
for (HTTPMethodConvertible element: blah) {
System.out.println(element.getHTTPMethodType());
}
}
static interface HTTPMethodConvertible {
public String getHTTPMethodType();
}
static enum LibraryEnum implements HTTPMethodConvertible {
FIRST("first"),
SECOND("second"),
THIRD("third");
String httpMethodType;
LibraryEnum(String s) {
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
static enum ClientEnum implements HTTPMethodConvertible {
FOO("GET"),BAR("PUT"),BLAH("OPTIONS"),MEH("DELETE"),BLABLABLA("POST");
String httpMethodType;
ClientEnum(String s){
httpMethodType = s;
}
public String getHTTPMethodType() {
return httpMethodType;
}
}
}
Output
first
POST
Enums are not extensible. To solve your problem simply
turn the enum in a class
create constants for the predefined types
if you want a replacement for Enum.valueOf: track all instances of the class in a static map
For example:
public class MyType {
private static final HashMap<String,MyType> map = new HashMap<>();
private String name;
private String httpMethodType;
// replacement for Enum.valueOf
public static MyType valueOf(String name) {
return map.get(name);
}
public MyType(String name, String httpMethodType) {
this.name = name;
this.httpMethodType = httpMethodType;
map.put(name, this);
}
// accessors
public String name() { return name; }
public String httpMethodType() { return httpMethodType; }
// predefined constants
public static final MyType FIRST = new MyType("FIRST", "first");
public static final MyType SECOND = new MyType("SECOND", "second");
...
}
Think about Enum like a final class with static final instances of itself. Of course you cannot extend final class, but you can use non-final class with static final instances in your library. You can see example of this kind of definition in JDK. Class java.util.logging.Level can be extended with class containing additional set of logging levels.
If you accept this way of implementation, your library code example can be like:
public class EnumClass {
public static final EnumClass FIRST = new EnumClass("first");
public static final EnumClass SECOND = new EnumClass("second");
public static final EnumClass THIRD = new EnumClass("third");
private String httpMethodType;
protected EnumClass(String name){
this.httpMethodType = name;
}
}
Client application can extend list of static members with inheritance:
public final class ClientEnum extends EnumClass{
public static final ClientEnum CUSTOM_FIRST = new ClientEnum("custom_first");
public static final ClientEnum CUSTOM_SECOND = new ClientEnum("custom_second");
private ClientEnum(String name){
super(name);
}
}
I think that this solution is close to what you have asked, because all static instances are visible from client class, and all of them will satisfy your generic wildcard.
We Fixed enum inheritance issue this way, hope it helps
Our App has few classes and each has few child views(nested views), in order to be able to navigate between childViews and save the currentChildview we saved them as enum inside each Class.
but we had to copy paste, some common functionality like next, previous and etc inside each enum.
To avoid that we needed a BaseEnum, we used interface as our base enum:
public interface IBaseEnum {
IBaseEnum[] getList();
int getIndex();
class Utils{
public IBaseEnum next(IBaseEnum enumItem, boolean isCycling){
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
if (index + 1 < list.length) {
return list[index + 1];
} else if(isCycling)
return list[0];
else
return null;
}
public IBaseEnum previous(IBaseEnum enumItem, boolean isCycling) {
int index = enumItem.getIndex();
IBaseEnum[] list = enumItem.getList();
IBaseEnum previous;
if (index - 1 >= 0) {
previous = list[index - 1];
}
else {
if (isCycling)
previous = list[list.length - 1];
else
previous = null;
}
return previous;
}
}
}
and this is how we used it
enum ColorEnum implements IBaseEnum {
RED,
YELLOW,
BLUE;
#Override
public IBaseEnum[] getList() {
return values();
}
#Override
public int getIndex() {
return ordinal();
}
public ColorEnum getNext(){
return (ColorEnum) new Utils().next(this,false);
}
public ColorEnum getPrevious(){
return (ColorEnum) new Utils().previous(this,false);
}
}
you could add getNext /getPrevious to the interface too
#wero's answer is very good but has some problems:
the new MyType("FIRST", "first"); will be called before map = new HashMap<>();. in other words, the map will be null when map.add() is called. unfortunately, the occurring error will be NoClassDefFound and it doesn't help to find the problem. check this:
public class Subject {
// predefined constants
public static final Subject FIRST;
public static final Subject SECOND;
private static final HashMap<String, Subject> map;
static {
map = new HashMap<>();
FIRST = new Subject("FIRST");
SECOND = new Subject("SECOND");
}
private final String name;
public Subject(String name) {
this.name = name;
map.put(name, this);
}
// replacement for Enum.valueOf
public static Subject valueOf(String name) {
return map.get(name);
}
// accessors
public String name() {
return name;
}
Error:
...
Caused by: java.lang.ExceptionInInitializerError
...
Caused by: java.lang.ClassCastException:
class com.evopulse.ds2150.TechTrees$BuildingTechTree
not an enum
at java.util.EnumSet.noneOf(Unknown Source)
at java.util.EnumSet.of(Unknown Source)
at com.evopulse.ds2150.TechTrees$BuildingTechTree.<clinit>(TechTrees.java:38)
Here is a snippet of my enumeration
public enum BuildingTechTree {
//Name SoftName Requirements
NONE ("NULL", null),
--> This next line is where it crashes
BARRACKS ("Barracks", EnumSet.of(NONE),
WALLS_SANDBAGS ("Sandbag wall", EnumSet.of(NONE),
POWERPLANT ("Power plant", EnumSet.of(BARRACKS)),
GUARDTOWER ("Guard Tower", EnumSet.of(BARRACKS));
Replacing EnumSet.of(NONE) and EnumSet.of(BARRACKS) with null, lets initialization work, but breaks my code, due to missing data structure... obviously, but I did it to test the rest of my code wasn't somehow the cause.
Removing EnumSet.of(NONE) and replacing with just NONE, and the same for BARRACKS, and changing all related variables, constructor, and methods, that didn't work either... (and even couldn't use the contains.all, since is wasn't "applicable to my changed variable"... )
I extended this example, using the second implementation:
https://gamedev.stackexchange.com/a/25652/48573
I also tried retracing my steps by copying the example verbatim. added
private static Set<BuildingTechTree> techsKnown;
techsKnown = (BuildingTechTree.BIODOME);
test = TechTrees.researchTech(techsKnown);
to another class to be called from for testing initialization. and had to change
public boolean researchTech(BuildingTechTree tech) {
to static
This resulted in the same "in not an enum" error. I don't have any rep, to comment on his answer to point out the initialization error...
Added info for both current answers, as both solutions cause the same new error:
public class TechTrees {
private static Set<BuildingTechTree> techsKnown;
public TechTrees() {
techsKnown = EnumSet.of(BuildingTechTree.NONE); //Using this
techsKnown = EnumSet.noneOf(BuildingTechTree.class); //Or this
}
public static boolean researchTech(BuildingTechTree tech) {
if (techsKnown.containsAll(tech.requirements)) { //Causes null pointer
return true; //exception # techsKnown
}
return false;
}
Your declaration structure is so clever it's a shame it doesn't work. But EnumSet apparently needs the enum to be fully initialized first. It tries to fetch the array of constants from the enum so that, among other things, it knows how much space is needed for its internal bitset.
Here's one workaround. It uses a helper method that creates an ordinary set (HashSet) first, and then, in a static initialization block, it iterates the enum constants and replaces all the sets with EnumSets.
public enum BuildingTechTree {
// Named constants
//Name SoftName Requirements
NONE ("NULL", null),
BARRACKS ("Barracks", setOf(NONE)),
WALLS_SANDBAGS ("Sandbag wall", setOf(NONE)),
POWERPLANT ("Power plant", setOf(BARRACKS)),
GUARDTOWER ("Guard Tower", setOf(BARRACKS));
private final String softName;
private Set<BuildingTechTree> requirements;
private BuildingTechTree(String softName, Set<BuildingTechTree> requirements) {
this.softName = softName;
this.requirements = requirements;
}
private static Set<BuildingTechTree> setOf(BuildingTechTree... values) {
return new HashSet<>(Arrays.asList(values));
}
static {
for (BuildingTechTree v : values()) {
if (v.requirements == null) {
v.requirements = EnumSet.noneOf(BuildingTechTree.class);
} else {
v.requirements = EnumSet.copyOf(v.requirements);
}
}
}
}
You have a chicken and egg problem. You could refactor your enum to something like this:
public enum BuildingTechTree {
NONE("NULL"),
BARRACKS("Barracks"),
WALLS_SANDBAGS("Sandbag wall"),
POWERPLANT("Power plant"),
GUARDTOWER("Guard Tower");
static {
NONE.trees = EnumSet.noneOf(BuildingTechTree.class);
BARRACKS.trees = EnumSet.of(NONE);
WALLS_SANDBAGS.trees = EnumSet.of(NONE);
POWERPLANT.trees = EnumSet.of(BARRACKS);
GUARDTOWER.trees = EnumSet.of(BARRACKS);
}
private String name;
private Set<BuildingTechTree> trees;
private BuildingTechTree(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Set<BuildingTechTree> getTrees() {
return Collections.unmodifiableSet(trees);
}
}
EDIT:
regarding your second problem: you're accessing a static variable, from a static method. But this variable is initialized when the constructor of the class has been called (which is a huge design problem). Don't use non-final static fields. And don't initialize static fields from instance methods or constructors. That doesn't make sense. You don't set the color that all cars should have when constructing a car. Initialize your static fields statically:
public class TechTrees {
private static final Set<BuildingTechTree> TECHS_KNOWN =
EnumSet.of(BuildingTechTree.NONE);
public static boolean researchTech(BuildingTechTree tech) {
return TECHS_KNOWN.containsAll(tech.requirements));
}
}
Is it possible in Java to return the enum value without having to call a function to return the value, such as getFlag() in my example? If so, how?
public enum MessageFlags {
BIT0((short)1),
BIT1((short)2),
BIT2((short)4),
BIT3((short)8),
BIT4((short)16),
BIT5((short)32),
BIT6((short)64),
BIT7((short)128),
BIT8((short)256),
BIT9((short)512),
BIT10((short)1024),
set_freq(BIT0),
get_freq(BIT1);
short bitFlag = 0;
MessageFlags flag;
MessageFlags(short flag) {
this.bitFlag = flag;
}
MessageFlags(MessageFlags flag) {
this.flag = flag;
}
public short getFlag() {
return this.flag.bitFlag;
}
public short getValue() {
return this.bitFlag;
}
}
Just say MessageFlags.BITX and that will return the same value as getFlag()
You can import static MessageFlags.*; and say BITX.getFlag().
Here is a complete example:
A.java
package foo;
import static foo.B.*;
public class A{
public B value = BAR;
}
B.java
package foo;
public enum B{
BAR, BAZ, BOO
}
I followed #Jeremy's advice of this:
package foo;
import static foo.B.*;
and then I created a method called set_freq in my MessageFlags enum. I made this function static and had it return short. For example,
public static short set_freqflag() {
return BIT0.getFlag();
}
The semantics of set_freqflag are a little weird because you are not setting anything but I do not have a better name at the moment. This allows me to just state set_freqflag() rather than the longer way I was doing before.
I might be really late, but I'm writing to anyone who visits this topic for help.
If you have an enum, and you'd like to return a specific parameter of its values by default without calling a get function, you need to insert an #Override above your selected function, like:
public class Plants {
public enum Fruits {
APPLE ("sweet"),
GRAPEFRUIT ("sour");
private String taste;
Fruits (String taste) {
this.taste = taste;
}
#Override
public String getTaste() {
return this.taste;
}
}
}
And now you can call whichever enum value you'd like, without a get function:
Plants.Fruits.APPLE
And it'll return "sweet"
P.S. I'm not a professional programmer, please correct me if I've written something anti-conventional by accident.