I have a Java (for Android) code similar to this one:
enum MyEnum {
A, B, C
}
String f(MyEnum e) {
if (e == null) {
return null;
}
switch(e) {
case A: return "AA";
case B: return "BB";
case C: return "CC";
default: throw new IllegalStateException("invalid enum");
}
}
and I got the exception in the default clause thrown once! Can somebody explain if this is theoretically possible and how?
For example in C++ you can have an enum variable which value is non of the declared enum values, but I guess in Java you cannot do that, correct me if I am wrong.
I dont see how this could fail, but i would propose refactoring your enum to this:
enum MyEnum {
A("AA"),
B("BB"),
C("CC");
private final String value;
public MyEnum(String value){
this.value = value;
}
public String f(){
return value;
}
}
now you can still do the same operations, but it 100% safe to add new enums
public void foo(MyEnum enum){
System.out.println(enum.f());
}
Related
How to get value by Java enum class name and field name?
The sample code is as follows, but I don't know how to pass the enum class as a parameter.
public enum ErrorCodes1{
OK(0),
NOT_EXIST_USER(1),
FAIL_TO_SEND_MAIL(2),
...
}
public enum ErrorCodes2{
OK(0),
NOT_EXIST_USER(1),
FAIL_TO_SEND_MESSA(2),
...
}
public void foo1()
{
foo2(ErrorCodes1.class, "NOT_EXIST_USER");
foo2(ErrorCodes2.class, "NOT_EXIST_USER");
}
public void foo2(Enum EnumClass, String EnumText)
{
int code = xxxx; //I want to get code(1) via EnumText and EnumClass, but I don't know how to do it.
}
You can use the type Class as a param of your function foo2
public static void foo2(Class<?> enumClass, String enumText) {
int code = -1; // I want to get code(1) via EnumText and EnumClass, but I don't know how to do
// it.
switch (enumClass.getCanonicalName()) {
case "ErrorCodes2": {
ErrorCodes1 errorCode = ErrorCodes1.valueOf(enumText);
code = errorCode.ordinal();
}
case "ErrorCodes1": {
ErrorCodes1 errorCode = ErrorCodes1.valueOf(enumText);
code = errorCode.ordinal();
}
}
System.out.println(code);
}
After that, you can use valueOf to instantiate your enum from a string that contains the enum value. I don't think this is the best solution but its works.
PS: The param of a function begins with a lowercase letter.
Option A, simple: check for the type explicitly.
int code;
if (enumClass instanceof ErrorCodes1) {
code = ((ErrorCodes1) enumClass).valueOf(enumText).ordinal();
} else if (enumClass instanceof ErrorCodes2)
// repeat
This implies you can pass an error object itself, not necessarily its class. Unfortunately, switch does not work with Class type.
Option B, probably overkill: use Reflection.
public void foo2(Class<?> enumClass, String enumText) {
try{
Object resultingEnum = enumClass.getMethod("valueOf", String.class).invoke(null, enumText);
int code = (Integer) resultingEnum.getClass().getMethod("ordinal").invoke(resultingEnum);
// ...
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e ) {
// ignore: enumClass is not an expected class
}
}
This will suit you in case you have an unlimited number of ErrorCode enums, though it is a barely plausible situation.
I have task to change this if:
if (userDecision.equalsIgnoreCase("D")) {
return DirectoriesActivity.DELETE;
} else if (userDecision.equalsIgnoreCase("R")) {
return DirectoriesActivity.REPLACE;
} else {
return DirectoriesActivity.ADD_NEW_CONTENTS;
}
On something what will return just enum without using if. I have to use some enum properties but I don't know which one :/ Here is my enum:
public enum DirectoriesActivity {
DELETE,
REPLACE,
ADD_NEW_CONTENTS;
}
I tried to do something like this:
public enum DirectoriesActivity {
DELETE ("D"),
REPLACE ("R"),
ADD_NEW_CONTENTS ("A");
private String directoriesActivityCode;
private DirectoriesActivity(String directoriesActivityCode) {
this.directoriesActivityCode = directoriesActivityCode;
}
public DirectoriesActivity getEnum(String x){
//no idea what to do here
}
}
Or maybe somebody have some other idea?
You can add a Map lookup.
static Map<String, DirectoriesActivity> lookup = new HashMap<>();
static {
// iterate over all the values and
// put the value we want to lookup as the key to the map.
for(DirectoriesActivity da: values())
lookup.put(da.directoriesActivitCode, da);
}
public static DirectoriesActivity lookup(String s) {
// lookup the map we built in the static block.
return s == null ? null : lookup.get(s.toUppercase());
}
This way you can add as many codes as you want without having to change the code.
How about this:
public enum DirectoriesActivity {
DELETE ("D"),
REPLACE ("R"),
ADD_NEW_CONTENTS ("A");
private String directoriesActivityCode;
private DirectoriesActivity(String directoriesActivityCode) {
this.directoriesActivityCode = directoriesActivityCode;
}
public DirectoriesActivity getEnum(String x){
for (DirectoriesActivity directoriesActivity : values()) {
if (directoriesActivity.directoriesActivityCode.equals(x)) {
return directoriesActivity;
}
}
throw new IllegalArgumentException("Unknown value " + x);
}
}
Or in case you are using Java 8
return Arrays.stream(DirectoriesActivity.values())
.filter(directoriesActivity -> directoriesActivity.directoriesActivityCode.equals(userDecision))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Unknown value " + userDecision));
Important side note here is that this solution is performing a lot worse than the solution provided by Peter. But as long as performance is not an issue, I'd prefer a solution like this.
If you can change enum names to D, R, A then you can use built-in feature:
public enum DirectoriesActivity {D,R,A}
DirectoriesActivity activity = DirectoriesActivity.valueOf("D");
valueOf throws IllegalArgumentException if string is not match.
(I was astonished not to be able to find this question already on stackoverflow, which I can only put down to poor googling on my part, by all means point out the duplicate...)
Here is a toy class that returns the reverse of what you put into it. Currently it works on integers, but would require only very minor changes to work for String.
public class Mirror {
int value;
public int get() {
return reverse(value);
}
private int reverse(int value2) {
String valueString = value + "";
String newString = reverse(valueString);
return Integer.parseInt(newString);
}
private String reverse(String valueString) {
String newString = "";
for (char c : valueString.toCharArray()) {
newString = c + newString;
}
return newString;
}
public void set(int value) {
this.value = value;
}
}
What I'd like to do is make the class generic, but only for, say, two or three possible types. So what I want to write is:
public class Mirror<X, where X is one of Integer, String, or MagicValue {
X value
public X get(){
[...]
What's the correct syntax? My Google-fu is failing me... :(
EDIT: it appears there isn't a correct syntax and it can't appear to be done, so my main question is: why? this seems like the sort of thing that people might want to do before they made the class truly generic...
EDIT EDIT: Managed to work out the why with some labmates today, so added the relevant why answer below.
Unfortunately java does not provide such functionality directly. However I can suggest you the following work around:
Create parametrized class Mirror with private constructor and 3 static factory methods that create instance of Mirror with specific parameter:
public class Mirror<T> {
private T value
private Mirror(T value) {
this.value = value;
}
public static Mirror<Integer> integerMirror(Integer value) {
return new Mirror(value);
}
public static Mirror<String> stringMirror(String value) {
return new Mirror(value);
}
public static Mirror<MagicValue> magicMirror(MagicValue value) {
return new Mirror(value);
}
}
EDIT
Obviously you can (and probably should) separate the class Mirror from its creating, e.g. put the factory methods to separate class MirrorFactory. In this case the constructor should become package protected.
If you want to support large yet limited number of classes you can implement only one generic factory method
public static <T> Mirror<T> createMirror(T value) {
checkTypeSupported(value);
return new Mirror(value);
}
Method checkTypeSupported(value); may use some kind of metadatat (e.g. properties, JSON etc file) to get supported types. In this case however you will not enjoy the compile time validation.
Other solution is to require that all supported types extend certain base class or implement interface:
public class Mirror<T extends MyInterface> {}
But this solution seems does not match your requirements since you need Integer, String and MagicValue.
Various ways to do what you need...Here is another option. No getter or setter.
One instance of Mirror for each type to be handled. One reverse() method.
Tweak as necessary. Add error checking/handling.
public class Mirror<T> {
public T reverse(final T value) {
T result = null;
while (true) {
if (value instanceof String) {
System.out.println("Do for String");
result = value;
break;
}
if (value instanceof Integer) {
System.out.println("Do for Integer");
result = value;
break;
}
if (value instanceof JFrame) {
System.out.println("Do for JFrame");
result = value;
break;
}
throw new RuntimeException("ProgramCheck: Missing handler for type " + value.getClass().getSimpleName());
}
return result;
}
Tester:
final Mirror<String> testerString = new Mirror<>();
testerString.reverse("string");
final Mirror<Integer> testerInteger = new Mirror<>();
testerInteger.reverse(41);
testerInteger.reverse(42);
testerInteger.reverse(43);
final Mirror<JFrame> testerJFrame = new Mirror<>();
testerJFrame.reverse(new JFrame());
Results:
Do for String
Do for Integer
Do for Integer
Do for Integer
Do for JFrame
An alternative would be to just accept the fact that you have no control over the type hierarchy of String/Integer and create an interface to give a common type for the classes you do have control over
public int reverse(int value) {
return Integer.valueOf(new StringBuilder(value + "").reverse()
.toString());
}
public String reverse(String value) {
return new StringBuilder(value + "").reverse().toString();
}
public <T extends Reversible> T reverse(T value) {
value.reverse();
return value;
}
public interface Reversible {
public void reverse();
}
And if you only want one instance of the Mirror class...use a generic method.
public class Mirror {
public <T> T reverse(final T value) {
T result = null;
while (true) {
if (value instanceof String) {
System.out.println("Do for String");
result = value;
break;
}
if (value instanceof Integer) {
System.out.println("Do for Integer");
result = value;
break;
}
if (value instanceof JFrame) {
System.out.println("Do for JFrame");
result = value;
break;
}
throw new RuntimeException("ProgramCheck: Missing handler for type " + value.getClass().getSimpleName());
}
return result;
}
tester:
final Mirror tester = new Mirror();
String s = tester.reverse("string");
Integer i41 = tester.reverse(41);
Integer i42 = tester.reverse(42);
Integer i43 = tester.reverse(43);
JFrame j = tester.reverse(new JFrame());
results:
Do for String
Do for Integer
Do for Integer
Do for Integer
Do for JFrame
You can't bound a generic parameter to range of values. You could however restrict it programatically:
public abstract class AbstractMirror<T> {
T value;
protected AbstractMirror(Class<T> clazz) {
if (clazz != Integer.class && clazz != String.class && clazz != MagicValue.class)
throw new IllegalArgumentException();
}
public abstract T get();
protected abstract T reverse(T value);
}
You can use so-called "witness" types to make the compiler do what you want.
public interface Reversible< T > {
public static final class IntReversible implements Reversible< Integer > {}
public static final class StringReversible implements Reversible< String > {}
public static final class MagicReversible implements Reversible< MagicValue > {}
}
public abstract class Mirror< T, R extends Reversible< T > > {
// ...
}
public class IntMirror extends Mirror< Integer, IntReversible > {
// ...
}
However, the reason your example doesn't make any sense is because you gain virtually nothing from using a generic in this context. What possible algorithm will reverse an integer or a string or a MagicValue without resorting to awful run-time type-checking and casting? The code will be all three reverse algorithms, wrapped with a hideous if-ladder.
So here is the why (worked it out at work)
Generics are always from a subclass, although it looks like
Public class Thing<T> {}
will allow any type in there, really what it's saying is that it will allow any subtype of Object. I.e.
Public class Thing<T extends Object> {}
This is effectively working as inheritance, and indeed, the Oracle Website shows us this happening when the syntactic sugar is removed:
In the following example, the generic Node class uses a bounded type
parameter:
public class Node<T extends Comparable<T>> {
private T data;
private Node<T> next;
public Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
public T getData() { return data; }
// ...
}
The Java compiler replaces the bounded type parameter T with the first
bound class, Comparable:
public class Node {
private Comparable data;
private Node next;
public Node(Comparable data, Node next) {
this.data = data;
this.next = next;
}
public Comparable getData() { return data; }
// ...
}
...and so the answer turns out that the reason you can't limit the types in this way is because it effectively turns into multiple Inheritance, which is nasty, and which I'm happy to avoid....
I'm working with JsonElements and its addProperty method(s). A JsonElement has 4 overloaded addProperty methods which I'd like to compress down into one to make it easier to add properties. This is what I've written up to start, and I'm realizing that the tricky part is going to be figuring out if a string is a Number.
Any thoughts on how to improve this method?
public JsonElementBuilder addProperty(final String property, final Object value)
{
if (parent instanceof JsonObject) {
if (value instanceof Boolean) {
((JsonObject) parent).addProperty(property, (Boolean)value);
} else if (value instanceof Character) {
((JsonObject) parent).addProperty(property, (Character)value);
} else if (value instanceof Number) {
((JsonObject) parent).addProperty(property, (Number)value);
} else if (value instanceof String) {
if (isInteger((String)value))
{
((JsonObject) parent).addProperty(property, (Number)value);
} else {
((JsonObject) parent).addProperty(property, (String)value);
}
}
}
private boolean isInteger(String s) {
try {
Integer.parseInt(s);
} catch(NumberFormatException e) {
return false;
}
return true;
}
This is a typical scenario where subtype polymorphism helps. Do the following
interface I {
void do();
}
class A implements I { void do() { doA() } ... }
class B implements I { void do() { doB() } ... }
class C implements I { void do() { doC() } ... }
Then you can simply call do() on this.
If you are not free to change A, B, and C, you could apply the visitor pattern to achieve the same.
Can yo explain why you want to do that? Overloaded methods, like you call them, is called Polymorphism, and it´s just a great Java feature that precisely allows you to avoid that kind of code into your methods.
You can make a single call for all the different classes, and Java does the selection of the correct method consuming less resources than your if ... else code...
Thanks to polymorphism -and btw also thanks to inheritance- you can do this:
//Many different types...
boolean boolProp = true;
char charProp = 'a';
int intProp = 12;
double dblProp = 1.50;
String strProp = "Polymorphism rocks!";
//One method name for all types...
jsonElement.addProperty("prop1", boolProp);
jsonElement.addProperty("prop2", charProp);
jsonElement.addProperty("prop3", intProp);
jsonElement.addProperty("prop4", dblProp);
jsonElement.addProperty("prop5", strProp);
So... why the hell do you want to write yourself a method that does something that Java can do itself without any effort and much more efficiently?
I want to use an Annotation in compile-safe form.
To pass the value() to the Annotation i want to use the String representation of an enum.
Is there a way to use #A with a value from enum E ?
public class T {
public enum E {
a,b;
}
// C1: i want this, but it won't compile
#A(E.a)
void bar() {
// C2: no chance, it won't compile
#A(E.a.toString())
void bar2() {
}
// C3: this is ok
#A("a"+"b")
void bar3() {
}
// C4: is constant like C3, is'nt it ?
#A(""+E.a)
void bar4() {
}
}
#interface A {
String value();
}
Update
I need the String type in #A.
The point is i can do this
#A("" + 1)
void foo() {
}
But here the compiler claims "attribute value must be constant". Is'nt E.a constant ?
#A("" + E.a)
void foo() {
}
The problem is that you're smarter than the compiler :-)
E.a is a constant, but E.a.toString() is not. It looks like it should be, but the compiler can't figure that out.
The reason why "a"+"b" and "" + 1 work is that the compiler is smart enough to generate the constants at compile time.
When it sees "" + E.a, it uses E.a.toString(). The call to toString() is enough to throw it off.
Does E have to be an enum? You could try:
public final class E {
public static final String a = "a";
public static final String b = "b";
};
Make the value in the annotation of type E:
#interface A {
E value();
}
Then you can use
#A(E.a)