Lookup within the enum constants by constant specific data [duplicate] - java

This question already has answers here:
How to retrieve Enum name using the id?
(11 answers)
Closed 9 years ago.
I need to do look up in an enum by an int . The enum is as folows :
public enum ErrorCode{
MissingReturn(1,"Some long String here"),
InvalidArgument(2,"Another long String here");
private final int shortCode ;
private final String detailMessage;
ErrorCode(shortCode ,detailMessage){
this.shortCode = shortCode ;
this.detailMessage= detailMessage;
}
public String getDetailedMessage(){
return this.detailMessage;
}
public int getShortCode(){
return this.shortCode ;
}
}
Now Is need to have a lookup method that would take an int code and should return me the String message pertaining to that code that is stored in the Enum.Passing a "1" should return me the String "Some long String here". What is the best way to implement this functionality?
public static String lookUpMessageFromCode(int code){
}
P.S: Is the class EnumMap useful for this kind of use case? If yes,please let me know why?

Depending on the int values that you associated with your enum, I would add a static array of ErrorCodes, or a static Map<Integer,ErrorCode> to your enum class, and use it to do a lookup in the message from code method. In your case, an array is more appropriate, because you have values 1 and 2 which are small. I would also change the signature to return ErrorCode.
private static final ErrorCode[] allErrorCodes = new ErrorCode[] {
null, MissingReturn, InvalidArgument
};
public static ErrorCode lookUpByCode(int code) {
// Add range checking to see if the code is valid
return allErrorCodes[code];
}
The callers who need the message would obtain it like this:
String message = ErrorCode.lookUpByCode(myErrorCode).getDetailedMessage();

I would simply iterate through your Enum values and check the code. This solution lets you utilize the existing Enum with out creating another object to manage.
public enum ErrorCode {
MissingReturn(1, "Some long String here"),
InvalidArgument(2, "Another long String here");
private final int shortCode;
private final String detailMessage;
ErrorCode(int shortCode, String detailMessage) {
this.shortCode = shortCode;
this.detailMessage = detailMessage;
}
public String getDetailedMessage() {
return this.detailMessage;
}
public int getShortCode() {
return this.shortCode;
}
public static String lookUpMessageFromCode(int code) {
String message = null;
for (ErrorCode errorCode : ErrorCode.values()) {
if (errorCode.getShortCode() == code) {
message = errorCode.getDetailedMessage();
break;
}
}
return message;
}
public static void main(String[] args) {
System.out.println(ErrorCode.lookUpMessageFromCode(1));
System.out.println(ErrorCode.lookUpMessageFromCode(2));
}
}
One thing to note
The Enum constructor is missing the type information regarding its parameters.
ErrorCode(int shortCode, String detailMessage) {
this.shortCode = shortCode;
this.detailMessage = detailMessage;
}

Here is another option:
public static String lookUpMessageFromCode(int code){
for(ErrorCode ec:ErrorCode.values()){
if(ec.shortCode==code)
return ec.detailMessage;
}
return null;
}

Related

How to use variable of method from 1 class in 2 class via Java?

public static class One {
#Override
public String interact(String... values) {
String actualTextOne = "test";
return actualTextOne;
}
}
public static class Two {
#Override
public String interact(String... values) {
String actualTextTwo = "test";
/* Here I need to compare actualTextOne and actualTextTwo, but the problem is that I can't find solluction how to use actualTextOne in Two class*/
return actualTextTwo;
}
}
You cannot do that.
Please check variable scope in java.
https://www.codecademy.com/articles/variable-scope-in-java
A possible solution here is to call the method interact from the class One. Something like this
public static class Two {
#Override
public String interact(String... values) {
String actualTextTwo = "test";
One one = new One();
String actualTextOne = one.interact(values);
// compare values here
return actualTextTwo;
}
}
Why in your classes functions have parameters if you dont use it?
You can mark your class with static only if he is nested, else you need do like this:
class Two {
static public String interact(String... values) {
String actualTextTwo = "test";
return actualTextTwo;
}
}
String textOne = One.interact("");
String textTwo = Two.interact("");
System.out.println(textOne==textTwo);

Using an argument as an interface item

In the program I am making, I am trying to get a formatted season name for a given season(formatted so it . I keep the formatted names in an interface, since if I were to use a map, it would be unnecessarily regenerated, since I don't make an instance of TeamBuilder
The Seasons interface:
public interface Seasons {
/*
* Contains a formatted list of seasons.
*
* An interface is being used as an alternative to using a Map in the
* TeamBuilder class, since calling parseTeam would have to build
* mappings for the seasons each time it
* was called. This way, the formatted name can simply be grabbed
*/
final String Skyrise = "Skyrise";
final String Toss_Up = "Toss%20Up";
final String Sack_Attack = "Sack%20Attack";
final String GateWay = "Gateway";
final String Round_Up = "Round%20Up";
final String Clean_Sweep = "Clean%20Sweep";
final String Elevation = "Elevation";
final String Bridge_Battle = "Bridge%20Battle";
final String Nothing_But_Net = "Nothing%20But%20Net";
final String Starstruck = "Starstruck";
final String In_The_Zone = "In%20The%20Zone";
final String Turning_Point = "Turning%20Point";
}
The problem comes when I try to grab these seasons. My TeamBuilder class takes in an argument(String season), which is unformatted. My question is, is there any way that I can use a String argument for a method to get a specific item from an interface? This is the most preferable to using a HashMap, which would needlessly regenerate the same information
All these classes can be found on the Github page for this project.
If you want to do it in a typed way, you can use Enum for this:
enum Season{
Skyrise,Toss_Up, Sack_Attack;
#Override
public String toString() {
switch(this){
case Skyrise: return "Skyrise";
case Toss_Up: return "Toss%20Up";
case Sack_Attack: return "Sack_Attack";
default: return "";
}
}
}
public class main{
public static void printSeason(Seasons seasons){
System.out.println(seasons);
}
public static void main(String[] args) {
Seasons e = Seasons.Skyrise;
printSeason(e);
System.out.println(e);
}
}
Since the compiler internally invokes the toString(), you can pass the argument as a Seasons or a String like my example.
And if you still want to use a map without "unnecessarily regenerated" you can use a static field with static initializer like this:
class Seasons {
private static Map<String,String> map = new HashMap<>();
static {
map.put("Skyrise", "Skyrise");
map.put("Toss_Up", "Toss%20Up");
}
public static String getFormatted(String key){
return map.getOrDefault(key,"");
}
}
class main{
public static void main(String[] args) {
System.out.println(Seasons.getFormatted("Skyrise"));
}
}
Just to integrate on Snoob answer you can have enum with fields, so:
enum Season
{
Skyrise("Skyrise"),
Toss_Up("Toss%20Up"),
Sack_Attack("Sack%20Attack")
;
public final String fancyName;
private Season(String fancyName)
{
this.fancyName = fancyName;
}
}
You really have all the benefits without any drawback.

How to manipulate error code enum

I have the below code:
public enum CpAutoExecCode implements CpAutoErrorCode {
//TODO - List of the execution error codes
//Error code sample
GENERIC_EXECUTION_ERROR(200,"Generic execution error code description"),
MISSING_REQUIRED_FIELD(201,"Required field %s is missing from model : %s");
private final int number;
private final String description;
private CpAutoExecCode(int number,String description) {
this.number = number;
this.description = description;
}
#Override
public int getNumber() {
return number;
}
#Override
public String getDescription() {
return description;
}
}
i want to assign the required field and the object name in the %s .
does anyone have a simple way to do it?
You can use String.format() with CpAutoExecCode.getDescription():
String formattedMessage = String.format(MISSING_REQUIRED_FIELD.getDescription(),
myMissingField,
myModel);
It really depends on your usage of the class.
For instance, if you have a custom exception that takes in the enum, you can do something like this:
class MyException {
int code;
MyException(CpAutoErrorCode error, Object[] args) {
super(format(error.getDescription(), args));
}
private static String format(String error, Object[] args) {
// interpolate your string with the values
}
}
Or you can build the same type of structure on the enum class itself.

In Java, how to iterate on the constants of an interface?

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);
}
}

Questions about enum

If I have a Object
public class Genre {
private int id;
private int name;
}
And the id and name were been determined in advance, for example
if (id == 1)
name = "action";
else if (id == 2)
name = "horror";
My problem is how to create these two methods well
Genre.getName(1); // return "action";
Genre.getId("action"); // return 1;
I thought maybe I can use enum, like
public enum Genre {
ACTION(1), HORROR(2);
private final int id;
private final String name;
private Genre(int id) {
this.id = id;
this.name = getName(id);
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public static String getName(int i) {
switch(i) {
case 1 : return "action";
case 2: return "horror";
default :
return null;
}
}
}
But in this way, I have no idea how to
Genre.getId("action"); // return 1;
And im afraid i use enum not correctly.
Could you give me some advice? Thanks!
---
At first, What I want to do this is in my case i want to use id or name to find the name or id like
int id = 1;
Genre.getName(id); // return "action"
or
String name = "action";
Genre.getId(name); // return 1
And now thanks for all the advices, I realize why I want to do is
int id = 1;
Genre.getGenre(id); // return Genre that id = 1 and the name = "action"
or
String name = "action";
Genre.getGenre(name); // return Genre that id = 1 and the name = "action"
If you insist on using an enum for this, you can just use the existing enum facilities. The solution below assumes the enum name and ordinal may be used in place of your name and id fields:
public enum Genre {
// ordinal 0, name = "ACTION"
ACTION,
// ordinal 1, name = "HORROR"
HORROR;
}
public static void main(String[] args) {
int horrorOrdinal = 1;
Genre horrorGenre = Genre.values()[horrorOrdinal];
String horrorName = horrorGenre.name();
String actionName = "ACTION";
Genre actionGenre = Genre.valueOf(actionName);
int actionOrdinal = actionGenre.ordinal();
System.out.println(String.format("%s=%s %s=%s", horrorName, horrorOrdinal, actionName, actionOrdinal));
}
Output:
HORROR=1 ACTION=0
Another suitable way would be to use a map for the lookup, like Michał Šrajer suggested:
private static Map<Integer, String> genres = new HashMap<Integer, String>();
public static void main(String[] args) {
initGenres();
int horrorOrdinal = 2;
String horrorName = genres.get(horrorOrdinal);
String actionName = "action";
int actionOrdinal = getGenreIdByName(actionName);
System.out.println(String.format("%s=%s %s=%s", horrorName, horrorOrdinal, actionName, actionOrdinal));
}
private static void initGenres() {
genres.put(1, "action");
genres.put(2, "horror");
}
private static int getGenreIdByName(String genreName) {
for (Entry<Integer, String> entry : genres.entrySet()) {
if (entry.getValue().equals(genreName)) {
return entry.getKey();
}
}
throw new IllegalArgumentException("Genre not found: " + genreName);
}
Output:
horror=2 action=1
Design considerations:
In this example I chose to use the (fast) map lookup for id->name and wrote a seperate method (getGenreIdByName) to do the reverse lookup name->id. You could reverse that, or use a second map to make both lookups fast (at the cost of needing to maintain an extra map).
I chose to store the id and name in the map. You could also use the Genre class itself as the map value. This would allow you to easily add extra fields (like 'description') later on.
If you need to represent you genres in different languages, you can use ResourceBundles to localize the output. Create a language file in your classpath root.
In file genres_nl.properties:
horror=heel eng
action=actie
Where the _nl suffix in the filename indicates the language.
Then in your code, in initGenres:
ResourceBundle genreNames = ResourceBundle.getBundle("genres", new Locale("nl");
And when getting the genre name:
String horrorName = genreNames.getString(genres.get(horrorOrdinal));
Note that getString can throw the runtime exception MissingResourceException if the bundle is not found. To avoid this, make sure you create a 'default' bundle with no suffix (so in this case a file named 'genres.properties') which is automatically used in case no bundle for the used Locale can be found.
Try the valueOf(...) method:
void String getId(String name) {
//names are upper case, so account for that
//handling non-existent names is an excersize for you
valueOf(name.toUpperCase()).getId();
}
Note that there are better methods (like Thilo suggested), but if you have a string only, you might use that.
Edit: another note:
In your getName(int i) method, you might want to return ACTION.name() etc. in order to be more refactoring safe and use the correct case.
You can get its ID by calling Genre.ACTION.getId();
This should do it:
Genre.ACTION.getId()
And if you need to do it at run-time:
Genre.valueOf("ACTION").getId()
ACTION(1, "action"), HORROR(2, "horror");
is a easy way to do it.
But if you are require to do it more often i would suggest you to create your own class and use MAP<-"-,-"-> as micheal said.
Edit:----
As you said the rarely gonna change use this way-->
public enum Genre {
ACTION(0, "action"), HORROR(1, "horror"), ROMANCE(2, "romance"), COMEDY(5, "comedy");
public final int id;
public final String name;
private Genre(int id, String name) {
this.id = id;
this.name = name;
};
public final static int length = Genre.values().length;
public static String[] getGenre() {
String[] genreList = new String[length];
int i = 0;
for (Genre attribute : Genre.values()) {
genreList[i++] = attribute.toString();
}
return genreList;
}
#Override
public String toString() {
return this.name;
}
}
Please remember use this as Genre.HORROR.id
also note that using this way is best as per your requirement.
Why don't you use the Enum Constructor with id and String:
public enum Genre {
ACTION(1, "action"), HORROR(2, "horror");
}
public enum Genre {
ACTION(1, "action"), HORROR(2, "horror");
private final int id;
private final String name;
private Genre(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
}
If you need to access particular element by it's name, you need to do it this way:
Genre.valueOf("ACTION").getId()
However, if you need to do it often, and in more dynamic way, I suggest to create regular class, and to keep all data in some Map<String, Movie> container.

Categories

Resources