I'm trying to understand when can I use the enums in Java.
So, let's say I have three enums values :
enum Activity {
STUDENT, MECANICIAN, TEACHER
}
How can make use of this enum class in an existing Person class ? How is it persisted in a database?
class Person {
private String name;
private String age;
private String activity; // !!!
}
Thank you.
Just add the enum to Person:
class Person {
private String name;
private String age;
private Activity activity;
}
One way to persist this field is to use an ORM such as Hibernate, for example:
#Enumerated(EnumType.STRING)
private Activity activity;
would map the field to a text type field in the database.
They help to take the place of having to use abstract integers. Instead of job=1 it's job=STUDENT. Sure you could use numbers but your code will be hard to understand. Plus you can use activity as a necessary type. So whenever you have a function changeJob(int val) you can make it changeJob(activity val) to force one of your enigma being passed.
Enum is iterable, which is great, if you want to use the values like this:
public static String getStatusStr(Status s) {
return Messages.get("softDeleteable.status." + s.name());
}
public static List<DropDownData> getStatusDataSource() {
List<DropDownData> retval = new ArrayList<DropDownData>();
for(Status s : Status.values()) {
retval.add(new DropDownData(s.name(), getStatusStr(s) ));
}
return retval;
}
Where DropDownData is a simple value, label object, and Messages is for translating (Play framework)
Related
In my context, there is the possibility of optional values.
For example, in this database, the field iVisperas can be empty in multiple cases. I think is a bad practice to keep empty fields (?).
Into my code, I map the snapshot to one class.
I don't want to keep the field iVisperas as an empty field in Firestore but I don't know how to determine from the model class if this field exists or not.
How I can achieve this. This is my model class from the document. Actually, at getTituloVisperas method I check if field iVisperas is empty. If I want to create iVisperas field only when it contains data, how I can manage that into the model class?
public class MetaLiturgia {
private String fecha;
private int tiempo;
private String semana;
private String mensaje;
private String salterio;
private int color;
private String meta;
private String titulo;
private String iVisperas;
private int weekDay;
public MetaLiturgia() {
}
public String getTituloVisperas() {
if (iVisperas.equals("")){
return titulo;
}else{
return iVisperas;
}
}
//...
}
For example, in this database the field iVisperas can be empty in multiple cases.
Seeing that all the fields in your MetaLiturgia class are set to private, I assume that you are using a constructor and public getters. If you want that your iVisperas property not to hold any value then simply do not instantiate it in the constructor or create another constructor without it.
If I want to create iVisperas field only when it contains data, how I can manage that into the model class?
In that case, you should use a Map and update that document only when the value for your iVisperas property is available.
I think is a bad practice to keep empty fields (?).
There is no benefit in keeping empty fields as long as are not needed. Remember, every property count in that 1 MiB (1,048,576 bytes) maximum size for a document.
According to Suhas Ch's answer, please also note that a property of type String which is empty ("") and a property which holds null, occupy the same amount of space in a document.
Edit:
Another possible solution is to assign a default value, in this case, 0, right inside the model (MetaLiturgia) class.
While creating field, set the type for iVisperas as null
and in the model class
public class MetaLiturgia {
private String fecha;
private int tiempo;
private String semana;
private String mensaje;
private String salterio;
private int color;
private String meta;
private String titulo;
private String iVisperas;
private int weekDay;
public MetaLiturgia() {
}
public String getTituloVisperas() {
if (iVisperas.equals(null)){
return titulo;
}else{
return iVisperas;
}
}
//...
}
When do you know if the field is empty?
You could delete attribute from your model class and create another class which inherits fro your model class.
There you can add the value. When it comes to saving the object, you wont write the field if its not used.
But I dont know if this is worth the effort, since you will have to create a newObject of the subclass once your attribute is used.
I have an adapter class with work with ArrayList KeyValue Object.
class Adapter {
public Adapter(ArrayList<KeyValue> items){
.....
}
}
and
class KeyValue {
String name;
int id;
...
}
but the problem is I have ArrayList of Fruits like this
class Fruits {
String fruitName;
int id;
.....
}
is there any way to use ArrayList of Fruits without convert them to ArrayList of KeyValue "performance issue". and without using reflection"again performance issue"? maybe create a connector class?
of course, the main problem is there is a lot of different objects like Fruits.
The short answer is no. You can, however declare a common base class though:
abstract class NamedObject {
String name;
int id;
};
but all your classes would have to inherit from it. If you can't change the definition of the classes, you use an additional object that can access the name and the id of the elements in the list:
interface Accessor<T> {
String getName(T obj);
int getId(T obj);
}
That would, of course affect performances.
Since I have a terrible memory, I like to put all the detnd I ails of data objects into enumerations, so I can use code completion in the IDE adon't have to keep referring back to get the name of a table or the name of a field. Usually I use some type of class containing only Enums for the purpose.
Lets say I have table of "Domains" (database source) "Tables" and "Fields" that look something like this:
public class DataObjectNames {
public enum Domains {
Domain1,
Domain2;
}
public enum Domain1Tables {
Customers,
Orders;
}
public enum Domain2Tables {
OrderItems,
Shipments;
}
public enum CustomerFields {
id,
email;
}
public enum OrderFields {
id,
customerId;
}
//fields for OrderItems and Shipments . . .
}
But suppose I wanted to be able to do something like:
Domain1.tables().Customers.fields(). //code completion supplies choices?
What I would like ot happen after I type the period is for autocomplete to provide a choice between .id and .email, much the same as it would if "fields" returned an object with two methods, or if I just typed
CustomerFields.
in the IDE.
In order for that to happen, it seems to me I somehow need to return not a specific instance of an enumeration, but the enumeration itself. I've tried various approaches like this:
public enum Domains {
Domain1 {
#Override
public Enum<?> tables() {
return Domain1Tables.foo();
} //Is there a method that will return the enum itself?
},
Domain2 {
#Override
public Enum<?> tables() {
return Domain2Tables.foo();
};
public abstract Enum<?> tables();
}
But of course I haven't been able to find a funciton foo() that returns the enum class itself.
Any thoughts?
You can't do this with enums because Java's class model doesn't work the way you would need in order for this style to work.
I haven't been able to find a function foo() that returns the enum class itself.
Returning the enum class itself is easy, you just do Domain1Tables.class, but that won't give you the completion you want because what it gives you is a Class<Domain1Tables> object, and that object doesn't have fields named Customers and Orders.
You want to be able to treat the "Domain1Tables" class as if it's an object and refer to the enum constants (which are effectively static final fields) as if they were members of that object, but Java simply doesn't do that.
If you give up on using enums for it, then you can simply have:
public class DataObjectNames {
public class Domains {
class Domain1 {
class Tables {
class Customers {
public static final String id = "id";
public static final String email = "email";
}
}
}
}
}
but in that case DataObjectNames.Domains.Domain1 wouldn't be a valid expression anymore (because it reference to a class scope, but not to an object.
There's probably a solution to what you're trying to do, but without more context I can provide anything more details than what's above.
In my app, I have a Spinner being filled from an enum:
ArrayAdapter<myEnum> enumAdapter = new ArrayAdapter<Stroke> (parentActivity.getApplicationContext(), R.layout.simple_spinner_item, myEnum.values());
enumAdapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
enumSpinner.setAdapter(strokeAdapter);
This uses an override of the enum's toString() method to get a friendly name for the enum values to display in the Spinner. Currently my enum has strings hardcoded for the friendly names but I'd like to move these to strings.xml to support localization.
However, toString doesn't have access to a Context so I'm not sure how to resolve the resource ids.
Is there any way of getting localised strings in the toString() method of an enum?
If I understand this correctly, the real question here is how to get a Context from your enum, so that you can call Context.getString() to get localized versions of the Strings you need.
One approach, would be to set a static member variable of type Context in your application's onCreate() method, which is described in this answer. The idea here is that every time your application gets created or recreated, you'll hold on to the application context in a variable that's easy to get to.
Then, pass in the resource ID in the constructor of your enum values, and use the Context in your toString() method.
For example:
public enum Example {
HELLO(R.string.hello),
WORLD(R.string.world);
private int mResourceId;
private Example(int id) {
mResourceId = id;
}
#Override
public String toString() {
return App.getContext().getString(mResourceId);
}
}
#Override
public String toString()
{
return App.getContext().getString(id);
}
It's important that your enum class doesn't have any ties to your activity because if you want to use it in another application then you won't be able to if you are referencing a static context.
So a better way would be to return the resource id of the string back to the activity and then let the activity grab the string using the id from there.
So from your enum class you would have a method looking something similar to this:
public int getResourceId()
{
return resourceId;
}
Then in your activity I would build up a list containing an arraylist:
final List<String> enumList = new ArrayList<String>();
for ( final MyEnum status : MyEnum.values() )
{
enumList.add( getString( status.getResourceId() ) );
}
Then you can use enumList with your ArrayAdapter. Bingo :)
So now you have no ties to the enum class, and so if you are building another app that needs to use the same enum class you can easily do so.
Use static Application is always a bad practice, because not only it breaks Instant Run, but also this is against the decoupling principle thus makes modularization difficult to implement. Not to mention Android actually supports multiple Applications in a single process.
For this reason, I'd suggest define an inner class for the enum as your adapter entries.
enum Example {
A(R.string.label_a),
B(R.string.label_b);
Example(#StringRes int label) { mLabel = label; }
private #StringRes int mLabel;
class Entry {
private final Context mContext;
Entry(final Context context) { mContext = context; }
#Override public String toString() { return mContext.getString(mLabel); }
}
}
Then, build an array of Example.Entry for the adapter.
Arrays.stream(Example.values()).map(item -> item.new Entry(context)).toArray(Example.Entry[]::new)
I'm not 100% sure I understand what you are asking.
Is there any way of getting localised strings in the toString() method of an enum?
You can certainly #Override the toString() method inside of your myEnum to change how it is displayed:
public enum myEnum {
ONE("1"),
TWO("2");
private String pretty;
private myEnum(String pretty) {
this.pretty = pretty;
}
#Override
public String toString() {
// you can localise this string somehow here
return pretty;
}
}
Hello I would like to create a Class which contains an array with the same class.
I tried with the code specified below, but the array i created has been infinite.
public class State {
private String Valor1;
private String Valor2;
private ArrayList arrayStatesAnteriores;
}
And i did the set and get with the refactor of netbeans
state.setArrayStatesAnteriores(arrayStateAnteriores);
But i have the problem of array being infinite. Any idea?
Here's the way I understand it: You have a class that represents a program's state in a given moment, and you want to keep a list of the state that the program has had, that's why you say it's an infinite list.
First the State class, which has two fields value1 and value2 one constructor which sets the two fields to the passed values:
public class State {
/**
* This is the constructor
*/
public State(String value1, String value2){
this.value1 = value1;
this.value2 = value2;
}
// Omiting getters/setters for brevety.
// This will be set by the constructor using the values that it
// receives as arguments
// e.g
// new State("My Val1","My Val2");
private String value1;
private String value2;
}
Then this class would be contained in an array of States
List<State> states = new ArrayList<States>();
Then you would use this classes in your main or other classes:
import State;
public class Program {
// This array holds the states that the program has had.
private static List<State> states = new ArrayList<State>();
public static void main(String[] args){
// ...
// Do something
// ...
// Save the states
states.add(new State("State 1","Value 1"))
// Save another state
states.add(new State("State 2","Value 2"))
// The arraylist now contains two states of the program.
}
}
Hope it helps feel free to ask more questions.
Use a List, and initialize it:
public class State {
private List<State> statesAnteriores = new ArrayList<State>();
}
First of all, just a few tweeks on your code:
ArrayList is just in implementation of the List interface. You don't have to use it when defining a member field.
you should define the type of the list elements, see generics in Java: http://docs.oracle.com/javase/tutorial/java/generics/index.html
so that would be
public class State {
private String Valor1;
private String Valor2;
private List<State> arrayStatesAnteriores;
}
And regarding your question, what do you mean by " the array is infinite"?
You mean it is null after you have set it?
state.setArrayStatesAnteriores(arrayStateAnteriores);
the reason for this may be you setting the value of the list with itself, which is null.
try something like this:
state.setArrayStatesAnteriores(new ArrayList<State>());