Why the order of declaration important for Java enums, I mean why does this give (compile time) errors
public enum ErrorCodes {
public int id;
Undefined;
}
but this one is fine:
public enum ErrorCodes {
Undefined;
public int id;
}.
It's not a very satisfying answer, but it's just how enums are defined in Java. See section 8.9 Enums in The Java Language Specification.
Because this is the syntax for enums. It could allow different orders however this may have been open to mistakes such as forgetting to place a type on a field and turning it into a enum value.
EDIT: The reason I say they could be in any order is that fields, methods, initialisers and constructors can be in any order. I believe the restriction is valid if it is to reduce mistakes. Even though fields/constructors/methods can be in any order its very common to see them in that order for readability.
Java Enum is a special kind of class. Its simple and mostly useful form does not contain custom fields:
public enum ErrorCodes {
Undefined, Defined, Foo, Bar
}
Compiler magic creates class that looks approximately like the following:
public class ErrorCodes {
public final static ErrorCodes Undefined = new ErrorCodes();
public final static ErrorCodes Defined = new ErrorCodes();
public final static ErrorCodes Foo = new ErrorCodes();
public final static ErrorCodes Bar = new ErrorCodes();
}
This compiler magic expects the fields definition right after the enum header.
Sun were so kind to allow us to add such fields that follow the definition of eunum members:
public enum ErrorCodes {
Undefined, Defined, Foo, Bar;
private String myField;
}
This is the reason that your custom code always must be defined after the enum fields.
Related
The below class doesn't have final keyword but its member variables are private and final and the class exposes no mutate/set methods. Is this class immutable or not?
public class Abc {
private final int id;
private final String name;
public Abc(int id, String name) {
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
}
The class itself is immutable, yes - if you create an instance of just Abc, no aspect of that can be changed after the instance has been created.
However, that doesn't mean that any code receiving a parameter of type Abc can assume it's immutable with all the benefits that carries... because the class isn't final. It's entirely possible for an object of a type compatible with Abc to be mutable:
public class Mutable extends Abc {
private String value;
public Mutable(int id, String name) {
super(id, name);
}
public void setValue(String value) {
this.value = value;
}
#Override public String toString() {
return value;
}
}
Now imagine you've got code which deals with an Abc:
public class AbcConsumer {
private final Abc abc;
public AbcConsumer(Abc abc) {
this.abc = abc;
}
// No need to create a defensive copy or anything like that...
// abc is immutable, right?
public Abc getAbc() {
return abc;
}
}
Here the consumer assumes it's fine to treat Abc as if it's an immutable class - but if someone creates an AbcConsumer by passing in a Mutable instance instead of "vanilla" Abc instance, it could cause problems.
That's why it's generally a good idea when you're creating an immutable type to make it final as well - that way any consumers know that if they receive a reference with that type, it's definitely immutable.
To put it another way: yes, the Abc class is immutable... but you can't assume that a reference with a compile-time type of Abc refers to an immutable object.
As presented, yes, the class is immutable.
The "final" keyword on a class declaration prevents it from being extended - it's not related to immutability (unless your variables are declared public or protected).
Edit; "not related" is a poor choice of words, please see Jon Skeet's answer below
No, it is most likely not.
A problem is terminology. What do you mean by class? If you mean this code, sure, it's immutable. But 'this code' is not something that is particularly relevant to the concept of immutability. That usually makes a lot more sense if we consider it: this type.
As in, is the type Abc immutable?
As in, given:
public void foo(Abc abc) { ... }
is it safe to assume that the received abc couldn't possibly change?
And then the answer is no. That is not safe to assume: The type Abc is mutable.
The reason is that someone could make this:
class SneakyAbc extends Abc {
private int id;
public void setId(int id) {
this.id = id;
}
public String getId() {
return id;
}
}
This is why immutable classes are virtually always made final, to fully guarantee it.
Depending on how fancy you want to paint with the brush of 'what does this term mean', if all methods of Abc are final, you can consider it immutable as well if you really want to: Whilst the class does not need to be immutable (a subclass can add a new non-final field and create getters and setters for this), all the stuff you can 'witness' from the Abc type, assuming you don't use reflection, do appear immutable.
Exactly what definition of immutable you go with would be required knowledge to delve any further.
Note that something like java.io.File has only final fields and is final, and yet, it has easily observable state that can be modified: just.. delete the file, and voila you can see it. You can pull similar stunts with an IdentityHashMap to create a faux but nevertheless very observable 'field'.
Thus, 'immutable' as a concept: Useful. As a boolean flag to bestow upon a certain type or some java source file: Not useful.
Records
Other Answers directly addressed your questions about immutability, class being marked final, and subclasses being mutable. I’ll add an alternative option to more briefly accomplish your goal of immutability: Records.
Java 16 brings the new records feature. If the main purpose of your class is to immutably and transparently carry data, define your class as a record. The compiler implicitly creates default constructor, getters, equals & hashCode, and toString.
A record is implicitly final, so no risk of a subclass becoming mutable.
Declare the properties in parentheses. By default, you need not put anything in the curly braces body of a record.
record Abc ( int id , String name ) {}
Instantiate like any other class.
Abc x = new Abc ( 42 , "Snuffleupagus" ) ;
The implicit getter methods are simply the property names. The JavaBeans-style get…/is… method naming is not used. (You could add such methods if required.)
System.out.println( x.name() ) ;
Snuffleupagus
It is mutable if its internal states can be changed after the class is created.
In your example, although there is no class final, the inside situations cannot be changed again because of final keyword. In this way, the class becomes immutable again
I want to ask about nested enums. I am working with old code and i found very strange construction that i not really good understand.
I have this enum :
public enum DbEngines {
ORACLE("oracle", "set define on", "set define off")
, POSTGRESQL("postgresql", "--TODO set define on", "--TODO set define off");
private final String dbEngine;
private String setOn;
private String setOff;
DbEngines(String dbEngine, String setOn, String setOff) {
this.dbEngine = dbEngine;
this.setOn = setOn;
this.setOff = setOff;
}
public String getSetOn() {
return setOn;
}
public String getSetOff() {
return setOff;
}
public String toString() {
return this.dbEngine;
}
}
I added private String to this enum, that are engine specific, so it is good place for me here. The problem is, that in some places in method declaration i see something like that
public someMethod(Enum<DbEngines> engine, ...)
And it worked perfectly without methods, but now, after changing, I couldn't call public getters of this enum. But if i change to :
public someMethod(DbEngines engine, ...)
it works without any problems with all public getters. Maybe someone could explain that?
Enum in Java is the base class for all enumeration types. One can think of it as similar to Object class.
Just like one can hold reference of object of any class using the reference of type Object, one can refer to an enumeration type using the reference of type Enum.
Object o = new Integer(10);
Enum e = DBEngine.ORACLE;
One cannot invoke a method present in inherited class but absent in superclass using the reference of superclass.
Similar explanation over here.
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.
I am creating a store for user preferences, and there are a fixed number of preferences that users can set values for. The names of the preferences (settings) are stored as an Enum:
public enum UserSettingName {
FOO,
BAR,
ETC
}
What I would like to be able to do is store a value type with the name so that the service will store the user's value with the correct Java type. For example, FOO might be a Long, and BAR might be a String. Up until now, we were storing all values as Strings, and then manually casting the values into the appropriate Java type. This has lead to try/catch blocks everywhere, when it makes more sense to have only one try/catch in the service. I understand that Enums cannot have generic types, so I have been playing around with:
public enum UserSettingName {
FOO(Long.class),
BAR(String.class),
ETC(Baz.class)
private Class type;
private UserSettingName(Class type) {
this.type = type;
}
public Class getType() {
return this.type;
}
}
I have a generic UserSetting object that has public T getSettingValue() and public void setSettingValue(T value) methods that should return and set the value with the correct type. My problem comes from trying to specify that generic type T when I create or retrieve a setting because I can't do something like:
new UserSetting<UserSettingName.FOO.getType()>(UserSettingName.FOO, 123L)
Sorry if this isn't exactly clear, I can try to clarify if it's not understood.
Thanks!
UPDATE
Both the setting name and value are coming in from a Spring MVC REST call:
public ResponseEntity<String> save(#PathVariable Long userId, #PathVariable UserSettingName settingName, #RequestBody String settingValue)
So I used the Enum because Spring casts the incoming data automatically.
Firstly you have to step back and think about what you're trying to achieve, and use a standard pattern or language construct to achieve it.
It's not entirely clear what you're going after here but from your approach it almost certainly looks like you're reinventing something which could be done in a much more straightforward manner in Java. For example, if you really need to know and work with the runtime classes of objects, consider using the reflection API.
On a more practical level - what you're trying to do here isn't possible with generics. Generics are a compile-time language feature - they are useful for avoiding casting everything explicitly from Object and give you type-checking at compilation time. You simply cannot use generics in this way, i.e. setting T as some value UserSettingName.Foo.getType() which is only known at runtime.
Look how it done by netty:
http://netty.io/wiki/new-and-noteworthy.html#type-safe-channeloption
They done it by using typed constants:
http://grepcode.com/file/repo1.maven.org/maven2/io.netty/netty-all/4.0.0.Beta1/io/netty/channel/ChannelOption.java#ChannelOption
EDIT:
public interface ChannelConfig {
...
<T> boolean setOption(ChannelOption<T> option, T value);
...
}
public class ChannelOption<T> ...
public static final ChannelOption<Integer> SO_TIMEOUT =
new ChannelOption<Integer>("SO_TIMEOUT");
...
}
EDIT2: you can transform it like:
class Baz {}
class UserSettingName<T> {
public static final UserSettingName<Baz> ETC = new UserSettingName<Baz>();
}
class UserSetting {
public <T> UserSetting(UserSettingName<T> name, T param) {
}
}
public class Test {
public static void main(String[] args) {
new UserSetting(UserSettingName.ETC, new Baz());
}
}
Enums are not the answer here. If you find yourself repeating code everywhere you could just create a utility class and encapsulate all the try/catch logic there. That would cut down on your code redundancy without majorly impacting your current code.
public class Util
{
public static MyObject getObjectFromString(String s)
{
try
{
return (MyObject)s;
}
catch(Exception e)
{
return null;
}
}
}
Then use as follows:
MyObject myObj = Util.getObjectFromString(string);
I could be wrong but I'm guessing from Why can't enums be declared locally in a method?
that, since an enum in Java cannot be declared locally, that therefore it is problematic for a method to return type Enum? I can declare that a method should return an Enum (see below) but how would one then go about implementing such a method to return anything other than null, or a reference to an Enum declared outside the method? My first inclination would be to investigate using Generics for this but I'd like to avoid any deadends if the SO community can help me avoid them.
private Enum resources() {
return null;
}
I think you're correct, it's only going to be able to either return null or an Enum declared somewhere else. But you don't necessarily have to specify that "something else" at compile time.
class EnumEnumerator<T extends Enum<T>> implements Iterable<T> {
private final Class<T> enumClass;
public EnumEnumerator(Class<T> enumClass) {
this.enumClass = enumClass;
}
public Iterator<T> iterator() {
T[] values = enumClass.getEnumConstants();
return Arrays.asList(values).iterator();
}
}
Later, you invoke it by specializing the generic constructor and passing in the enum class you're interested in:
class EnumEnumeratorDemo {
enum Foo {
BAR, BAZ, QUX;
#Override public String toString() {
return name().toLowerCase();
}
}
public static void main(String[] args) {
for (Foo f : new EnumEnumerator<Foo>(Foo.class)) {
System.out.println(f);
}
}
}
(Obviously this is a contrived example and in real life you should just call Foo.values(), but you get the idea.)
The entire point of the way Java does Enums is that they are typesafe--so you wouldn't return an Enum (that would be double-plus ungood) instead you return the actual type you define (like "Suit") which acts just like a class. Suit has 4 "Enumerated" instances.
If you were expecting a "Suit", what good would it be to return a "Rank" of 7? It would break everything!
Also if you passed an "Enum" or some generic value, you couldn't call methods on it. The coolest thing about TypeSafe Enums is that you can just get a "Suit" and call "Suit.getColor()" and fully expect to get the color of that suit. You could also have a ranksHigherThan(Suit s) which might fulfill:
assertTrue(SPADES.ranksHigherThan(HEARTS));
Or, more importantly:
suit1.ranksHigherThan(suit2);
(assuming they were both passed in and you don't know what they are)
Type safety is really amazing (even though it feels a little uncomfortable at first), embrace it.
All enums implement the interface Enum, so you can certainly write a method that returns an enum this way. But this method will return a single enum value. There is no way to return a generic value which encompasses the whole enum (apart from returning the class and doing reflection). You can however return all the enum values which is more or less what you want I think.
enum Resources { ONE, TWO, THREE }
private Enum<?>[] resources() {
return Resources.values();
}
One benefit of this approach is you can return more or less values for example:
enum Resources { ONE, TWO, THREE }
enum MoreResources { UN, DEUX, TROIS }
private Enum<?>[] resources() {
List<Enum<?>> resources = new ArrayList<Enum<?>>();
resources.addAll(Arrays.asList(Resources.values());
resources.addAll(Arrays.asList(MoreResources.values());
return resources.toList(new Enum<?>[] {});
}
An even better approach that is more typesafe is to have the enums of interest
implement a common interface e.g.
public interface Resources {}
enum SomeResources implements Resources { ONE, TWO, THREE }
enum MoreResources implements Resources { UN, DEUX, TROIS }
private Resources[] resources() {
List<Resources> resources = new ArrayList<Resources>();
resources.addAll(Arrays.asList(Resources.values());
resources.addAll(Arrays.asList(MoreResources.values());
return resources.toList(new Resources[] {});
}
You can add additional methods to the interface to provide more functionality.
What are you trying to accomplish? This is a way to return an Enum:
public class Test
{
public static void main(String args[])
{
System.out.println(doit());
}
public enum Foo {
BAR,
BAZ;
}
public static Enum doit() {
return Enum.valueOf(Foo.class,"BAR");
}
}
But, I'm guessing this is not what you are going for?
Yes, it definitely is possible.
private Enum getRetentionPolicy() {
return java.lang.annotation.RetentionPolicy.SOURCE;
}
If your question is about declaring Enums, you may declare them:
in their own java file, similar to a top-level class;
within a java file belonging to another class, similar to a static inner class;
Not totally sure what your goal is, but if you wanted to return a generified method (i.e. one that would be overridden) you might have something like the following:
public class MyEnumClass<T extends Enum<T>> {
public T resources() {
//do stuff here
}
}
Not entirely sure what you would gain there, although it can be beneficial if you are talking about different sets of Enums and their elements.
If you are talking about the Enum class (i.e. the percursor to Iterator) as far as I know it has not been generified, so I am not sure generics would help much here.
You can refer to a value of an enum by its name, e.g. Suit.SPADES.
You can iterate over all values by using the values() method and pick one of the values.