Java: Getting an array of ENUM elements - java

Is there a better way of creating arrays from elements of an enum:
public static enum LOGICAL {
AND ("&", "AND"),
OR ("||", "OR");
public final String symbol;
public final String label;
LOGICAL(String symbol, String label) {
this.symbol=symbol;
this.label=label;
}
}
public static final String[] LOGICAL_NAMES = new String[LOGICAL.values().length];
static{
for(int i=0; i<LOGICAL.values().length; i++)
LOGICAL_NAMES[i]=LOGICAL.values()[i].symbol;
}
public static final String[] LOGICAL_LABELS = new String[LOGICAL.values().length];
static{
for(int i=0; i<LOGICAL.values().length; i++)
LOGICAL_LABELS[i]=LOGICAL.values()[i].label;
}

Personally I wouldn't expose them as an array, whose contents can be changed by anyone. I'd probably use an unmodifiable list instead - and probably expose that via a property rather than as a field. The initialization would be something like this:
private static final List<String> labels;
private static final List<String> values;
static
{
List<String> mutableLabels = new ArrayList<String>();
List<String> mutableValues = new ArrayList<String>();
for (LOGICAL x : LOGICAL.values())
{
mutableLabels.add(x.label);
mutableValues.add(x.value);
}
labels = Collections.unmodifiableList(mutableLabels);
values = Collections.unmodifiableList(mutableValues);
}
(If you're already using Guava you might even want to use ImmutableList instead, and expose the collections that way to make it clear that they are immutable.)

No. That seems the proper way. Even if there was some utility, it would rely on reflection
If you are using it often cache it in the enum

If you use your values very frequently and your enumeration gets bigger use Maps. Declare the following in your class.
private static EnumMap<LOGICAL,String> symbols = new EnumMap<LOGICAL, String>(LOGICAL.class);
and then just below it:
static{
for(LOGICAL i : LOGICAL.values().)
symbols.put(i, i.symbol);
}
then you can use symbols.values() or symbols.get(LOGICAL.AND) etc.

Related

Iterate over Two Class with constants and load their fields into a HashMap

I have two java class with constants, For Ex:
public class FirstClass {
public static final String STRING_A = "STRING_A";
public static final String STRING_B = "STRING_B";
public static final String STRING_C = "STRING_C";
...
}
public class SecondClass {
public static final String STRING_AA = "STRING_AA";
public static final String STRING_BA = "STRING_BA";
public static final String STRING_CA = "STRING_CA";
...
}
Now, I want to load these constants into a,
Map< String,String> classPropertyMap = new HashMap<>(); in Such a way that, Key for this map must be a constant from FirstClass and corresponding value must be a constant from SecondClass.
If it was just one class I could use reflection to load the fields, now since the constants are from two class, how could this be done?
Finally after loading the map, the contents of the map must be something like this:
First element : key and value is < STRING_A, STRING_AA>
Second element : key and value is < STRING_B, STRING_BA>
Third element : key and value is < STRING_C, STRING_CA>
I think if you really need it, the most robust way is to put the properties to a map explicitly.
I mean map.put(FirstClass.STRING_A, SecondClass.STRING_AA); and so on.
If you use reflection you rely on the properties and their declaration order never changes. If some new property is introduced in the library, it can break your code.
Try something like below, seems you can achieve.
FirstClass first = new FirstClass();
Field[] fields = first.getClass().getFields();
SecondClass second = new SecondClass();
Field[] fields1 = second.getClass().getFields();
Try This:
FirstClass first = new FirstClass();
String[] firstStrings = first.getStrings();
//Makes a String array, and fills it with the strings from the first class.
SecondClass second = new SecondClass();
String[] secondStrings = second.getStrings();
//Makes a String array, and fills it with the strings from the second class.
HashMap<String, String> classPropertyMap = new HashMap<String, String>();
int i = 0;
//Now put strings with the same index number from both arrays into the
//HashMap
while(i <= firstStrings.length()){
classPropertyMap.put(firstStrings.get(i), secondStrings.get(i);
i++;
}
Hope that works!

Java8 Lambda expression to iterate over enum values and initialize final member

I have a static enum like this:
private static enum standardAttributes {
id, gender, firstname, lastname, mail, mobile
}
I need all the values as String. Therefore I have a method like this:
public static List<String> getStandardRecipientsAttributes() {
List<String> standardAttributesList = new ArrayList<String>();
for (standardAttributes s : standardAttributes.values())
standardAttributesList.add(s.toString());
return standardAttributesList;
}
There is no need to create the same List everytime this method is called. So I created a static member:
static final List<String> standardAttributesList;
static {
standardAttributesList = getStandardRecipientsAttributes();
}
This is all fine, but I wonder if there is a fancy Lambda expression to replace the method. Something like this:
Arrays.asList(standardAttributes.values()).forEach((attribute) -> standardAttributesList.add(attribute.toString()));
Two questions:
Can I avoid the Arrays.asList wrapper?
How can I handle the compiler error: The blank final field standardAttributesList may not have been initialized?
You can do
static final List<String> standardAttributesList =
Stream.of(values())
.map(Enum::name)
.collect(Collectors.toList());
This will create a Stream from an the array of values, apply the .name() method to each one and finally collect all the results into a List.

How to reference a variable using a string

I am attempting to reference a variable using a certain string but have no idea how to do it. I know that I can use if statements if I really had to but I am sure that there is a simple way. An example is a Integer named dog. I would try to access the Integer using another string that contained the text dog.
private int dog;
String anything = "dog";
Is there anyway this is possible? Thanks!
Try this:
// use a map for referring to a value given its name
Map<String, Integer> vars = new HashMap<String, Integer>();
// for example, let's use these values
String anything = "dog";
int dog = 10;
// bind a value to a name
vars.put(anything, dog);
// retrieve the value, given its name
vars.get(anything);
=> 10
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
public static void main(String[] args) {
Map<String, MyObject> mapping = new HashMap<>();
}
Or new HashMap<String, MyObject>(); for pre java 7
You should use a Map of String to Integer. For example,
public static void main(String[] args) {
java.util.Map<String, Integer> dogMap = new java.util.HashMap<String, Integer>();
dogMap.put("Snoop", 10);
dogMap.put("doggy", 15);
dogMap.put("dog", 20);
System.out.println(dogMap);
}
Which outputs
{doggy=15, Snoop=10, dog=20}
Two options: create a Map<String, Object> that connects the two, or use reflection. I prefer reflection.
in order to get the field:
public class Test {
private int dog = 10;
private String anything = "dog";
public static void main(String[] args){
Test obj = new Test();
Object field = obj.getClass()
.getDeclaredField(obj.anything)
.get(obj);
System.out.println(field);
}
}
Output:
10
Create an object of the class that you will use. Then use the getDeclaredField() method on the class of that object. This will look into the private fields that are set, getField() holds only the public fields. That's it.
I've removed the try-catch from the post because it just clutters it.

Get variable by name from a String

Example code:
int width = 5;
int area = 8;
int potato = 2;
int stackOverflow = -4;
Now, say I want to have the user input a string:
String input = new Scanner(System.in).nextLine();
Then, say the user inputs potato. How would I retrieve the variable named potato and do stuff with it? Something like this:
System.getVariable(input); //which will be 2
System.getVariable("stackOverflow"); //should be -4
I looked up some things and did not find much; I did find a reference to something called "the Reflection API," but that seems too complicated for this one simple task.
Is there a way to do this, and if so, what is it? If "Reflection" does indeed work and if it is the only way, then how would I use it to do this? The tutorial page for it has all sorts of internal stuff that I can't make any sense of.
EDIT: I need to keep the Strings in the variables for what I am doing. (I can't use a Map)
Using reflection doesn't seem like a good design for what you're doing here. It would be better to use a Map<String, Integer> for example:
static final Map<String, Integer> VALUES_BY_NAME;
static {
final Map<String, Integer> valuesByName = new HashMap<>();
valuesByName.put("width", 5);
valuesByName.put("potato", 2);
VALUES_BY_NAME = Collections.unmodifiableMap(valuesByName);
}
Or with Guava:
static final ImmutableMap<String, Integer> VALUES_BY_NAME = ImmutableMap.of(
"width", 5,
"potato", 2
);
Or with an enum:
enum NameValuePair {
WIDTH("width", 5),
POTATO("potato", 2);
private final String name;
private final int value;
private NameValuePair(final String name, final int value) {
this.name = name;
this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
static NameValuePair getByName(final String name) {
for (final NameValuePair nvp : values()) {
if (nvp.getName().equals(name)) {
return nvp;
}
}
throw new IllegalArgumentException("Invalid name: " + name);
}
}
Variable names are only available at compiler time. Reflection only gives access to class declarations and items declared inside them, but not to local variables. I suspect that a Map of some kind will be a more appropriate solution to your real problem. Specifically, check out HashMap and TreeMap.
Instead of trying to find the value of a variable name, why don't you use a Map with a key/value pair?
Map<String, Integer> vars = new HashMap<String, Integer>();
vars.put("width",5);
vars.put("area",8);
vars.put("potato", 2);
vars.put("stackOverflow",-4);
Then you could access the inputs like so:
vars.get(input); //would be 2
vars.get("stackOverflow"); //would be -4
I have another solution without a map :
class Vars {
Integer potato, stack;
public Vars(a,b) {
potato=a;
stack=b;
}
}
Object object=(Object)new Vars(1,2);
Class<?> c = object.getClass();
Integer result=(Integer)c.getField("potato").get(object);
I have a solution for this problem that does not involve using a map. I ran into this technique because we had several variables that needed to be update based on something within the variable name itself. However, the best way to do this is by using the getters/setters rather than the variables.
After you create your class, you can access the methods by creating Method objects and invoking them individually.
public class FooClass
private String foo1;
private String foo2;
public String getFoo1();
public String getFoo2();
FooClass fooClass = new FooClass();
Method mFoo1 = fooClass.getClass().getMethod("getFoo" + increment + "()");
mFoo1 .invoke(fooClass);
However, this would not be limited to only incremental numbers, as long as you can get the string to match the method exactly.
String value = "Potato";
Method mPotato = myClass.getClass().getMethod("get" + value+ "()");
mPotato.invoke(myClass);
Very redundant, but you can keep your variable names when using a map:
int width = 5;
int area = 8;
int potato = 2;
int stackOverflow = -4;
Map<String, Integer> map = new HashMap<>();
map.put("width", width);
map.put("area", area);
map.put("potato", potato);
map.put("stackOverflow", stackOverflow);
But a statement like this:
width = 42;
would not change the value in the Map:
String input = "width";
map.get(input); // <-- still returns 5.
Only a new call of put fixes that:
width = 42;
map.put("width", width);
// or
map.put("width", 42);

Strange string array declaration Syntax

private final String[] okFileExtensions = new String[] { "csv" };
Would someone please explain why {} is written after a String array declaration?
Thanks.
It's an array of one element. In this case containing the String "csv".
When written as part of a declaration, this can be written in a more concise form:
private final String[] okFileExtensions = { "csv" };
Multiple-element arrays use commas between values. There needn't be any values at all.
private final String[] okFileExtensions = { "csv", "tsv" };
private final String[] noFileExtensions = { };
It may be worth noting that although the reference is final the array is not. So you can write:
okFileExtensions[0] = "exe";
A way to get around this is to switch to collections and use an unmodifiable implementation:
private final Set<String> okFileExtensions = Collections.unmodifiableSet(
new HashSet<String>(Arrays.asList({
"csv"
}));
JDK8 is intended to have enhancement to collections that will make this more concise. Probably List and Set literals within the language. Possibly:
private final Set<String> okFileExtensions = { "csv" };
Collections should generally be preferred over arrays (for reference types).
That's the Java's valid syntax for array declaration.
You may use that when you are passing an array without declaring a variable:
public void printArray( String [] someArray ) {
for( String s : someArray) {
System.out.println( s );
}
}
And invoke it like this:
printArray( new String [] { "These", "are", "the", "contents"} );
The curly braces can only be used when declaring the array so the following is not allowed:
Stirng [] a;
a = {"on", "two"};
Creating an array of strings inline.
I think a less verbose (also confusing) declaration would have been :
private final String[] okFileExtensions = {"csv"};

Categories