is it possible to define an enum with int identifiers? - java

My question is "is it possible to have an int identifier in an enum?"
I'm developping a java program and I need to have identifiers that contains numbers and letters but eclips doesn't accept it.
for exapmle
public enum Tag{
5F25,
4F,
.
.
.
}
Do anyone know if there is any way to solve this problem!
Thank you

Enum instances must obey the same java language naming restrictions as other identifiers - they can't start with a number.
If you absolutely must have hex in the name, prefix them all with a letter/word, for example the enum class itself:
public enum Tag {
Tag5F25,
Tag4F,
...
}
or maybe with an underscore and all-caps:
public enum Tag {
TAG_5F25,
TAG_4F,
...
}
etc

You're trying to bend the laws and conventions of programming. I suggest you take a different approach.
Enums can have constructors. They are usually private, because "instances" of the enum are created inside it. You can provide any info you want (e.g. id, name, keyword etc.).
In this example, I've implemented the enum with just one parameter in the constructor, which is the unique ID you're needing.
public enum Tag
{
TAG_1(1),
TAG_2(2),
TAG_3(3);
private final int id;
private Tag(final int id)
{
this.id = id;
}
public int id() // Objective C style. Can be getId()
{
return id;
}
/**
* Bonus method: get a Tag for a specific ID.
*
* e.g. Tag tagWithId2 = Tag.getTagForId(2);
*/
public static Tag getTagForId(final int id)
{
for (final Tag tag : values())
if (tag.id == id)
return tag;
return null;
}
}

In a word, No. Java enum's are basically syntactic sugar for the typesafe enum pattern. This means that the enum is a list of java identifiers: Their names have to follow all the rules for identifiers. One of those rules is that identifier names cannot start with a number.

Related

What's the best way to change attributes of objects stored in an ArrayList or HashMap?

I have to do a little exercise (homework, like a friendlist) in Java, and i'm a little stuck on one of the tasks that i have to implement in my program.
The exercise is about storing some friend-objects with a variety of attributes in a container-class and implementing some methods in the container-class for various tasks on the friend-objects.
The overall exercise is not a problem at all, but i'm quite unconvinced that my solution is the way to go. I hope you can give me some tips here.
The method that is left over, should be something like a "updateFriend" method, with which you can set the value of a given attribute to a new value, straight from the container-class.
I've already set up my friend-class with a handfull of attributes (e.g. prename, lastname, date of birth, adress, and so on) an getters/setters for all of them. I've also implemented the container-class (as an ArrayList), but i can't seem to find an elegant way to implement this specific method. My updateFriend()-method right now takes three parameters.
1.The specific id of the friend-object
2.The name of the attribute that i want to change
3.The new value of the attribute
It uses an enum to check if the entered attribute is an existing attribute and if yes, the method searches the ArrayList for the object that contains that attribute and should overwrite the existing value. It gets a little bulky, as i have implemented a switch on the enum, that calls the fitting setter-method for each attribute of the friend, if the type in attribute exists at all.
So basically the friend-class looks like this:
public class Friend {
private static int friendCount = 1;
private String firstname;
private String lastname;
private LocalDate dateOfBirth;
private String phonenumber;
private String mobilenumber;
private String eMail;
private Adress home;
private int friendID;
//Getters & Setters
...
}
The method that gives me problems in the container-class looks something like this at the moment:
public void updateFriend(int id, String toChange, String newValue)
{
for(Attribute a : attribute.values())
{
if(String.valueOf(a).equalsIgnoreCase(toChange))
{
for(Friend f : friends)
{
int counter = 1;
if(f.getID() == id)
{
switch(a)
{
case FIRSTNAME:
{
f.setPreName(neuerWert);
break;
}
//a case for each attribute
}
I'm quite certain that my take on the given method is messy, slow, and cumbersome. What would be an elegant way of solving this?
Excuse my wording and thanks in advance, greets.
I would suggest 3 performance improvements.
Use HashMap instead of List with key as id. Since, id will be unique, it will take O(1) time to get the relevant object for modification instead of spending O(n) time on List iteration.
You can change the type of toChange parameter from String to enum. This will avoid enum to String conversion and then comparing it.
Since, you are already doing validation of the attribute to be modified and you must be following standard java convention while naming your getters and setters, you can use reflection to call the method on the Friend object by creating the method name from attribute name like set{Attributename}.
Okay, lets start using the enum Attribute to handle all the changes (Since you already holding the attribute values)
Attribute Enum
public enum Attribute {
FIRSTNAME("fname", (friend, name) -> friend.setFirstname(String.valueOf(name))),
LASTNAME("lname", (friend, lname) -> friend.setLastname(String.valueOf(lname))),
DATEOFBIRTH("dob", (friend, dob) -> friend.setDateOfBirth((LocalDate) dob)),
PHONENUMBER("pno", (friend, pno) -> friend.setFirstname(String.valueOf(pno))),
MOBILENUMBER("mno", (friend, mno) -> friend.setFirstname(String.valueOf(mno)));
private String attributeName;
private BiConsumer<Friend, Object> attributeSetter;
public static Attribute getAttributeSetterByName(String attributeName) {
return Arrays.stream(Attribute.values())
.filter(attribute -> attribute.getAttributeName().equalsIgnoreCase(attributeName))
.findFirst()
.orElseThrow(() -> new RuntimeException(String.format("Invalid Attribute name - %s", attributeName)));
//.orElse(null);
}
//Getter, Setter & Args Constructor (Use Lombok to reduce Boiler Plate code)
}
Update Logic
public void updateFriend(int id, String toChange, String newValue) {
Attribute attribute = Attribute.getAttributeSetterByName(toChange);
for (Friend friend : friends) {
if (friend.getId() == id) {
attribute.getAttributeSetter().accept(friend, newValue);
break;
}
}
}
You can use a java.util.function.Consumer<T> object to change an object inside your container where you have all the type safety you get. Instead of having magic strings and string arguments for values, which might not be even for string fields, you can work directly on the objects type:
public void updateFriend(int id, Consumer<Friend> c) {
// find the friend object
Friend found = null;
for (Friend f: this.friends) {
if (f.getId() == id) {
found = f;
break;
}
}
if (found == null) {
throw new IllegalArgumentException("There is no friend object with the given id");
}
// use the friend object.
c.accept(found);
}
You can use this method like this:
container.updateFriend(42, f -> f.setVorName("abc"));
container.updateFriend(9, f -> f.setAddress(some_address_object));

How to inject property values into enum?

I'm using Spring to resolve property values from properties file, usually with #Value("${my.property}").
Now I have an enum that should have an application-wide configurable static number. For example:
public enum PersonType {
ADULT, CHILD;
private static final int MAX_CHILD = 17;
public static PersonType fromAge(int age) {
return age <= MAX_CHILD ? CHILD : ADULT;
}
}
How could I make the max child age configurable and injectable by Spring?
It's an interesting question, how one handles variables that is the same for all objects of the class and does not change during runtime, and at the same time is allowed to be configurable between executions. Since the first two prerequisites dictate that the variable should be static and final (e.g. a constant), the third really doesn't fit in, meaning that there will be no pretty way to achieve all three (reflection is needed, or one has to drop either the static or the final constraint).
Since there is no pretty solution to the way things are modeled now, I think the wisest would be to take a step back and rethink the placement of the variable: Is it necessary to keep this logic in the enum itself? What is different when changing the value of the constant, the enum itself, or something else? In what cases does this constant have to change it's value?
In your example it might be that different countries have different thresholds for what is regarded as adult, or that the threshold changes, then maybe a small service that determines which PersonType a Person has is the right way to go.
#Service
public class PersonTypeService {
#Value("${threshold.for.adulthood}")
private int thresholdForAdulthood;
public PersonType determinePersonType(final Person person) {
if (person.getAge() >= thresholdForAdulthood) {
return PersonType.ADULT;
}
return PersonType.CHILD;
}
}
In general I like to let enums only answer the "what", and leave the "how" and the "why" to domain classes and services. In the example, all the enum needs to know is the values it provides a person, why it should provide a certain value, or how it is determined, does not belong in the enum.
Moving the logic to get proper enum based on configurable age can be one of the solution
class PersonTypeFinder
{
private int maxChildAge; // set this from spring
....
public PersonType getPersonType(int age)
{
return age <= maxChildAge ? PersonType.CHILD : PersonType.ADULT;
}
}
enum PersonType
{
ADULT, CHILD;
}

Is it possible to have an enum class with enums of two or more words?

I have to choose from several types of genres for books and I was thinking using enums for this, but there are several genres composed by two or more words like "Medical, Health & Fitness", "Art & Photography", "Science Fiction", etc.
public enum Genero {
Action, Comedy, Drama, Computers, Novel, Science Fiction
}
But I got a syntax error for "Science Fiction". I tried putting it with double quotes and simple quoutes, but neither worked. This enum is going to be use as a attribute for Book class.
No, it's not possible. Enum names must be valid Java identifiers - that means, no spaces. The usual convention is to declare enum names in all upper-case characters and separate words using an underscore, like this:
public enum Genero {
ACTION, COMEDY, DRAMA, COMPUTERS, NOVEL, SCIENCE_FICTION
}
It is not possible. It is possible, however, to use an underscore (Science_Fiction) in the name. You can also override the toString method to return whatever you want it to (since it appears you are going for a human-readable name for your enums):
public enum Genero {
ACTION("Action"), COMEDY("Comedy"), DRAMA("Drama"), COMPUTERS("Computers"), NOVEL("Novel"), SCIENCE_FICTION("Science Fiction");
private final String toString;
private Genero(String toString) {
this.toString = toString;
}
public String toString(){
return toString;
}
}
This might be what you want:
static private enum EnumExample {
R("Sample emun with spaces"),
G("Science Fiction");
final private String value;
EnumExample(String s) {
value = s;
}
}
System.out.println(EnumExample.G.value);
System.out.println(EnumExample.valueOf("G").value);
Science Fiction
Science Fiction

take the value of enum and covert it to String

I should take from a variable enum its value and transform it to string.how can i do?
here it is the type enum:
public enum State{
b,c,p;
};
now i have to insert into an object String one value.
You might use enum.name orenum.toString to get the name of the enum constant, or enum.ordinal to get the ordinal position.
you can use name() or toString(), so :
State aState = State.c;
String strState = aState.name();
See here the official java reference for more information...
State.b.toString() will return "b". The same goes for the other ones.
Usually,
State state = ...;
String string = state.toString();
should work, but it is not recommended since someone might override toString for some other purpose.
Instead the method you are looking for is
String string = state.name();
As an aside, your enumerated stated should always be all in capitals, and they should have descriptive names. It's not a language rule, but a convention. For example enum State { ON, OFF, PAUSED; }.
I tend to do something more complicated, but I find that it's more flexible:
public enum MyEnumeration {
SOME_NAME("Some Name"),
OTHER_THING("Other Thing"),
...
MORE_VALUES("More Values"),
private final String displayName;
private MyEnumeration(String displayName) {
this.displayName = displayName;
}
public String getDisplayName() {
return displayName;
}
}
This way, I use standard capitalization for my enums in code, but can have a more presentable name for them.
This trick can also be used to replace ordinal, by initializing a number, and then you don't need to worry about rearranging your enums.
Method #1: Using the built-in toString() and name() methods
If you want to print a String that is the same as the value of the State, then you can use the toString() method, or the name() method.
System.out.println(State.b); // Prints "b"
System.out.println(State.c); // Prints "c"
System.out.println(State.p); // Prints "p"
Method #2: Using a constructor to create a custom mapping
If you want to have a custom String associated with each of those states, you can use a constructor to associate a particular value with each enum value:
public enum State{
b("State B"), c("State C"), p("State P");
private String longName;
private State(String longName) {
this.longName = longName;
}
#Override
public String toString() {
return this.longName;
}
};
Of course, if you don't want to break the default toString() usage, you can create a different method called getFullName(), for example, to return the custom value.

nested enum-why is it used?

I have seen constructs with an enum declared inside an enum. What is this used for ?
Enums in Java can't be extended, so if you wanna collate strongly-related enums in one place you can use these nested enum constructs. For example:
public enum DepartmentsAndFaculties
{
UN (null, "UN", "University"),
EF (UN, "EF", "Engineering Faculty"),
CS (EF, "CS", "Computer Science & Engineering"),
EE (EF, "EE", "Electrical Engineering");
private final DepartmentsAndFaculties parent;
private final String code, title;
DepartmentsAndFaculties(DepartmentsAndFaculties parent, String code, String title)
{
this.parent = parent;
this.code = code;
this.title = title;
}
public DepartmentsAndFaculties getParent()
{
return parent;
}
public String getCode()
{
return code;
}
public String getTitle()
{
return title;
}
}
Here, inner enums consist of {parent enum, code, title} combinations. Example usage:
DepartmentsAndFaculties cs = DepartmentsAndFaculties.CS;
cs.getTitle();
You can see the power of nested enums when constructing hierarchical entities/enums.
You might mean an Enum as an inner type. This is most typically seen when the outer type is a class or an interface, but I suppose there isn't any reason this couldn't be done with enum as an outer.
Inner types are partly about code organization. They can be useful in avoiding creating a bunch of separate files when you have a few types that are related. Sometimes it can make type name more intuitive. For instance, see Map class and its inner Entry class. Most external references to Entry would use Map.Entry format, which is very readable.
The other reason for inner types is that if outer type is a class or an enum, then inner type can be non-public. This is useful for hiding types that are implementation details of the outer type.
I have used nested enums in rare cases where I wanted to enforce a naming convention on the enum values, if additions of new names would have implications for operations or other folks. Here's one example:
public enum MessageTemplateName {
account_verify,
vendor_job_request,
account_job_confirmed,
vendor_job_confirmed,
account_friend_request,
account_job_accepted,
vendor_job_accepted_by_other;
/** Make sure you tell operations if you're adding a new recipient */
private enum Recipient { account, vendor }
private Recipient recipient;
private String messageName;
MessageTemplateName () {
final int firstUnderscore = name().indexOf('_');
recipient = Recipient.valueOf(name().substring(0, firstUnderscore));
messageName = name().substring(firstUnderscore+1);
}
public String getTemplateUrl (String baseUrl) {
if (!baseUrl.endsWith("/")) baseUrl += "/";
return baseUrl + recipient.name() + "/" + messageName + ".vm";
}
}
I'm using an Enum because I want to be able to pass around a generic "message template name" in various places. As you can see, the first part of the enum name corresponds to a directory on a server, and the remainder of the name refers to a Velocity template file name. If fellow engineers started introducing new constants, I'd want to make sure they were filed under the appropriate "recipient", or if a new recipient legitimately needs to be created, that it's a conscious effort to do so, and you'll inform operations (create the directory in production, put any monitoring/permissions in place, etc).
There's a decent argument that, if at some point your Enum becomes too complex, you can replace it with a class/class hierarchy coupled with a much simpler enum. Not sure where I draw the line, but I suppose the above is heading in that direction.

Categories

Resources