enum generalInformation {
NAME {
#Override
public String toString() {
return "Name";
}
},
EDUCATION {
#Override
public String toString() {
return "Education";
}
},
EMAIL {
#Override
public String toString() {
return "Email";
}
},
PROFESSION {
#Override
public String toString() {
return "Profession";
}
},
PHONE {
#Override
public String toString() {
return "Phone";
}
}
}
I have that information are avaiable in enum.
How to print all enum values like: print.generalInformation?
That outputs:
Name
Education
Email
Phone
How to pass that enum generalInformation as an arg in another function?
System.out.println(java.util.Arrays.asList(generalInformation.values()));
Your second part... Just the same as an interface or a class
Firstly, I would refactor your enum to pass the string representation in a constructor parameter. That code is at the bottom.
Now, to print all enum values you'd just use something like:
// Note: enum name changed to comply with Java naming conventions
for (GeneralInformation info : EnumSet.allOf(GeneralInformation.class)) {
System.out.println(info);
}
An alternative to using EnumSet would be to use GeneralInformation.values(), but that means you have to create a new array each time you call it, which feels wasteful to me. Admittedly calling EnumSet.allOf requires a new object each time too... if you're doing this a lot and are concerned about the performance, you could always cache it somewhere.
You can use GeneralInformation just like any other type when it comes to parameters:
public void doSomething(GeneralInformation info) {
// Whatever
}
Called with a value, e.g.
doSomething(GeneralInformation.PHONE);
Refactoring using a constructor parameter
public enum GeneralInformation {
NAME("Name"),
EDUCATION("Education"),
EMAIL("Email"),
PROFESSION("Profession"),
PHONE("Phone");
private final String textRepresentation;
private GeneralInformation(String textRepresentation) {
this.textRepresentation = textRepresentation;
}
#Override public String toString() {
return textRepresentation;
}
}
With your current values, you could actually just convert the name to title case automatically - but that wouldn't be very flexible for the long term, and I think this explicit version is simpler.
Since Java 8 I would suggest the following solution:
public static String printAll() {
return Stream.of(GeneralInformation.values()).
map(GeneralInformation::name).
collect(Collectors.joining(", "));
}
In applications, it's good practice to separate data from presentation. It allows the data to be used in different user interfaces, it makes the data objects more lightweight, and it allows for the future possibility of internationalization.
With that in mind, it's good to avoid strongly coupling the display name to the enum constant. Fortunately, there is a class which makes this easy: EnumMap.
public class ApplicationUI {
private final Map<GeneralInformation, String> names;
public ApplicationUI() {
names = new EnumMap<>(GeneralInformation.class);
names.put(GeneralInformation.NAME, "Name");
names.put(GeneralInformation.EDUCATION, "Education");
names.put(GeneralInformation.EMAIL, "Email");
names.put(GeneralInformation.PROFESSION, "Profession");
names.put(GeneralInformation.PHONE, "Phone");
assert names.keySet().containsAll(
EnumSet.allOf(GeneralInformation.class)) :
"Forgot to add one or more GeneralInformation names";
}
public String getNameFor(GeneralInformation info) {
return names.get(info);
}
}
If you are still on Java 1.7 this is what worked for me:
String genInfoValues = "";
boolean firstRun = true;
for (generalInformation info : generalInformation.values()){
if (firstRun) {
firstRun = false;
genInfoValues += info.name();
} else {
genInfoValues += ", " + info.name();
}
}
values() on the enum returns an array. So, it would be simple to do the following to:
System.out.println(Arrays.toString(generalInformation.values()));
Related
Lets say I have a class to model an item in a game like so:
public class Item {
private final EnumItem type;
public Item(EnumItem type) {
this.type = type;
}
public Item(String name) {
this.type = EnumItem.fromName(name);
}
}
public enum EnumItem {
MACHINE_GUN("machine_gun"),
SWORD("sword"),
BAT("bat"),
DEFAULT("default");
private final String name;
public EnumItem(name) {
this.name = name;
}
public String getName() { return name; }
public static EnumItem fromName(String name) {
for(EnumItem i: EnumItem.values()) {
if(i.name.equals(name)) {
return i;
} else {
return EnumItem.DEFAULT;
}
}
}
}
Assume that .equals() and .hashCode() of Item are overridden correctly to compare the internal Enum.
Now I want a way to distinguish these items with a getter in Item: should I return an Enum or the String name? Is it good practice to return an Enum in general? Or is there a better way to distinguish these Items? Because returning the enum kind of looks like exposing the rep to me and I don't want my colleagues to use EnumItem directly to compare Items.
The approaches I thought of are the following:
string getName() to do something like item1.getName().equals("machine_gun");
EnumItem getEnum() to do item1.getEnum().equals(EnumItem.MACHINE_GUN);
item1.equals(new Item("machine_gun"));
static name(String name) { new Item(name) } to do item1.equals(Item.name("machine_gun"));
I don't know what should I do, I'd appreciate some insight from experienced programmers.
I know they look like they would from context, but in my use case these items have no special functionality that would justify extending from the base Item class.
Is this good practice? Sure, you're using aggregation since Item doesn't depend on EnumItem, which is fine. That being said, could it be done better? Sure. Is the alternative I provide the only solution? No.
Alternative
If you want this to be extensible, consider using an interface to represent an item. Then allow the interface to extend this interface to provide some standard types. Alternatively you could use composition or aggregation to define a type inside EnumItem that implements the Item interface to ensure that equals/hashcode for the Item are always override and adhere to some contract.
interface Item {
String key();
}
enum EnumItem implement Item {
private final String key;
EnumItem(String key) {
this.key = key;
}
#Override
public String key() {
return key;
}
}
class AbstractItem implements Item {
// constructor, override name()
}
Item item = EnumItem.FOO_BAR;
Item item2 = new AbstractItem("FooBar");
Item item3 = () -> "FooBar";
This question already has answers here:
Generating Enums Dynamically
(4 answers)
Closed 2 years ago.
I'm trying to create an Enumeration in Java. I did a code I created a comboBox with the enum values and it was correct. The problem is that in that case I knew the values I wanted ComboBox to have.
Now I'm trying to create a ComboBox in SceneBuilder with an object characteristic.
I receive from a file a lot of tasks and all of them have it own reference. I want to create an enum with all the references with the objective that user chose one task from the reference in the ComboBox.
Here is the Task code in portuguese (referencia means reference):
//This is a constructor of Tarefa (task):
public Tarefa(String referencia, String designacao, String descricaoInformal, String descricaoTecnica, int duracaoEstimada, Double custoEstimado) {
this.referencia = referencia;
this.designacao = designacao;
this.descricaoInformal = descricaoInformal;
this.descricaoTecnica = descricaoTecnica;
this.duracaoEstimada = duracaoEstimada;
this.custoEstimado = custoEstimado;
}
public String getReferencia() {
return referencia;
}
I was creating other JavaClass creating something like this:
public enum Prioridade {
BAIXA {
public String toString() {
return "Baixa";
}
},
ABAIXO_NORMAL {
public String toString() {
return "Abaixo do Normal";
}
},
NORMAL {
public String toString() {
return "Normal";
}
},
ACIMA_NORMAL {
public String toString() {
return "Acima do Normal";
}
},
ELEVADO {
public String toString() {
return "Elevado";
}
},
TEMPO_REAL {
public String toString() {
return "Tempo Real";
}
};
}
But in that case I knew the values I wanted enum to have.
How can I create an Enum not knowing from the beggining the values it will have? I only know the type: String.
You can use static method of enum valueOf(String str)
For example Prioridade.valueOf("ACIMA_NORMAL")
How to print any class instance in Java? Similar to JSON.stringify() in Javascript. Not necessary JSON, any format of output will do.
public class User {
public String name, password;
public int age;
public ArrayList<String> phones;
public static void login() {
//do something
}
}
User X = new User;
X.name = "john connor";
X.password = "skynet";
X.age = "33";
X.phones.add("1234567");
X.phones.add("7654321");
System.out.println(printClass(X))
Should output something like:
{ name:"john connor", password: "skynet", age: "33", phones:
["1234567", "7654321"], login: void function() }
You can use Apache's commons-lang's ToStringBuilder.reflectionToString
Of course, reflection is slow, so only do this with your test code. for normal use, please use eclipse's "Source" menu -> generate toString() (or intellij's generate toString()) which gives you a decent string.
There could be many ways to achieve what you need. Though i would be interested in why you need.
Override the toString() method.
see: http://www.javapractices.com/topic/TopicAction.do?Id=55
If the generation algorithm gets too long, then consider a separate class say UserPrettyPrinter.
public interface UserPrettyPrinter {
string print(User);
}
public class PrintUserInJSON implements UserPrettyPrinter {
string print(User user) {
//implement the algo here
}
}
you can also implement:
public class PrintUserInXML implements UserPrettyPrinter {
string print(User user) {
//implement the algo here
}
}
Either in conjugation to number-2 or as a standalone class, you can write
public class PrintObjectBasicAlgo {
String print(Object obj) {
/* i write pseudo code here. just ask if you cannot implement this
this would help: http://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html
Class class = Obj.getClass();
Filed[] allVariables = class.getAllFieldsByReflection();
ArrayList<String> keys = new ArrayList<String>;
ArrayList<String> values = new ArrayList<String>;
for(Field field : allVariables) {
Object value = reflectionGetValueOfField( field, obj );
keys.add( field.getName());
values.add(value.toString());
}
now that you have the keys and values, you can generate a string in anyway you like
*/
}
}
You may see Visitor Pattern. it might be helpful.
You have two options here. The simple one is just to override the toString function for your class. I dont see why you dont do this really. In this case its as simple as
String toString(){
return "{ name:\""+name+", password: \""+passowrd....
}
The second option is to use reflection. This would be slightly (though not really) better if you had some sorta external class used for "printing classes". The pseudo code for that would be
StringBuilder s = new StringBuidler();
for(Field f : fields){
s.append(f.getName() + "\" :\"" + f.get()+ "\"");
}
return s.toString();
However this would be costly as reflection always is. Also if you just properly override the toString functions in the first place your printClass function could literally just be
String printClass(Object o){ return o.toString();}
Which of course again begs the question of why do you need a printClass function?
One option is to use Google Gson.
import java.util.ArrayList;
import java.util.List;
import com.google.gson.Gson;
class Project {
private int year = 1987;
private String name = "ROBOCOP-1";
private boolean active = false;
private List<String> list = new ArrayList<String>() {
{
add("PROTECT THE INNOCENT");
add("UPHOLD THE LAW");
add("SERVE THE PUBLIC TRUST");
add("CLASSIFIED");
}
};
}
public class GsonExample {
public static void main(String[] args) {
Project obj = new Project();
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println(gson.toJson(obj));
}
}
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.
I have a Hashtable of type Hashtable
I've loaded several strings as keys, one of which is "ABCD"
However, later when I go to look up "ABCD", the Hashtable returns null instead of the associated object. Further the keyset contains "ABCD", but a request to containsKey("ABCD") returns false.
Is this because String objects are inherently different objects?
If so, what is the write way to store information in a Hashtable if I want to use Strings as keys?
public class Field {
private String name;
private DataType dataType;
public Field(String name, DataType dataType) {
this.name = name;
this.dataType = dataType;
}
public String getName() {
return name;
}
public DataType getDataType() {
return dataType;
}
public String toString() {
return name;
}
}
public class Record {
private Hashtable<String, Data> content;
public Record(Field[] fieldList) {
this.fieldList = fieldList;
content = new Hashtable<String, Data>();
System.out.println(fieldList.length);
for(Field f : fieldList) {
content.put(f.getName(), new Data());
}
}
public void add(String field, String s) {
// ERROR OCCURS HERE IN THIS METHOD !!!
System.out.println(field);
for(String ss : content.keySet()) {
System.out.print(" [ " + ss + " ] ");
}
System.out.println();
System.out.println(content.containsKey(field));
System.out.println(content.get(field));
content.get(field).add(s);
}
}
public class Data {
private Vector<String> lines;
private int index;
public Data() {
lines = new Vector<String>();
index = 0;
}
public void add(String s) {
System.out.println("adding");
lines.add(s);
}
public String nextLine() {
try {
return lines.elementAt(index++);
} catch (ArrayIndexOutOfBoundsException aioobe) {
return null;
}
}
}
Works for me!
import java.util.Hashtable;
public class StrMap {
public static void main(String[] args) {
Hashtable<String,Object> map = new Hashtable<String,Object>();
map.put("ABCD", "value");
System.err.println(map.containsKey("ABCD"));
}
}
Yo have probably made some other error. Reduce the problem to the smallest complete compilable program that still demonstrates the problem. You'll probably find the problem straight away. If you don't, at least you will have a question that we can answer.
(Also Map and HashMap is that way to go. Hashtable is useful if you are using a pre-Java 2 API (Java 2 is comfortably over a decade old now!).)
Hashtable is a Java 1.0 data structure. I wonder why you're not using a Map?
If java.lang.String is the key type, I'd say you're being hosed by something else that's impossible to guess without posting code.
It's hard to pinpoint the root cause without an SSCCE from your side.
At least, the common causes are:
You're not using the Hashtable you think you're using. System.out.println() it to verify.
The String is actually in a different case, e.g. "ABcD" instead of "ABCD".
The String is surrounded with some whitespace which you needs to trim() first.
That said (and unrelated to the actual problem), I strongly recommend to use the improved HashMap instead of the legacy Hashtable. Here's a Sun tutorial about maps.
Can you also post the exact output you get from the following method when field is "ABCD"?
public void add(String field, String s) {
// ERROR OCCURS HERE IN THIS METHOD !!!
System.out.println(field);
for(String ss : content.keySet()) {
System.out.print(" [ " + ss + " ] ");
}
System.out.println();
System.out.println(content.containsKey(field));
System.out.println(content.get(field));
content.get(field).add(s);
}