4

When I make enums that hold some fields, like my Settings enum, I like to make them public final to avoid lots of ( and ) keystrokes:

public enum Settings {
  SETTING_TEST("bool_setting1", false),
  USERNAME("user_name", "me")
  ;

  public final String name;
  public final Object default_val;
  Setnames(String n, Object d) {
    name = n;
    default_val = d;    
  }
}

This enum is then applied to look up (or set the default) settings in some hashmap (encapsulated in more sophistiated class). This design allows to control the setting names over the whole project (since enum names can be refactored, unlike strings).

My teacher warned me about this design though, and there are some answers suggesting that you can regret designing your project with public final without encapsulation.

I'm not only asking for rules and conventions but also your experience (the help center doesn't say anything negative about asking for opinions, so I do so). While I'd gladly even expand the question on other languages that support features in question, I'm not sure this wouldn't make the question too broad - which is why I think we should stick to Java only.

Edit:

The SE GUI asks me to explain how is my question different from the one I linked to. Other people already pointed out in comments the difference, but let's repeat it:

Most answers on the other question point out problems not applicable to enums. Often we use getXXX encapsulation to allow classes extend our class properly. But we cannot extend from enum. Generally, despite similar syntax, enums are substantially different from classes and interfaces.

  • 1
    possible duplicate of Using public final rather than private getters – Bart van Ingen Schenau Mar 9 '15 at 10:55
  • I really don't see how is this question any different from the one you linked ... – Gábor Angyal Mar 9 '15 at 10:56
  • Why would encapsulation lead to lots of () in this case? Do you need to refer to names and default values of Settings all over your application? – COME FROM Mar 9 '15 at 11:31
  • @COMEFROM Of course I do. These settings are used actively, real time (not so realtime to be worth caching in variables though). An to make sure there are no null pointer error, my settings class accepts second argument whenever you try to fetch a setting - the setting default value. And it's common sense that the name is needed wherever you retrieve a setting. – Tomáš Zato Mar 9 '15 at 14:17
  • 1
    First off, it may and may not be different, and the fact that it may be different is enough to warrant the question. And in fact, enums are different from classes in many ways: they are not inheritable, they are not instantiatable, we don't usually persist them, etc. so, that's plenty different as far as I am concerned. Furthermore, the accepted answer of the question that this question is allegedly a duplicate of lists a number of reasons why public final might be bad, and every single one of them (or nearly all of them) is inapplicable to enums. – Mike Nakis Mar 9 '15 at 15:30
5

My personal opinion is that public final is generally fine everywhere, not just on enums.

In my book, there are only two reasons for not using public final, and these are:

  • Allowing for future changes which might require altering the nature of the fields while maintaining binary compatibility with external code. (A getter would allow this.)

  • Typing 'get' and letting autocomplete show me everything that I can read from an object without having to scroll up and down in the autocomplete list to see if besides getter methods there are also any public final fields that I can read (whose names presumably do not start with get.)

As for the points made by the answer that you linked to, none of them are applicable to enums.

So, even if you don't agree that public final is generally fine everywhere, still, at least for enums, it is really-really fine.

  • And, I guess, the trouble with writing opinion answers to opinion questions is that people might downvote an opinion answer just because they have a different opinion. – Mike Nakis Mar 9 '15 at 14:11
  • There's plethora of programming practices and they are all opinions. Computer doesn't care how you write code, this contest proves it with great results (check the freaky source). It's humans and their opinions that make programming practices a thing. – Tomáš Zato Mar 9 '15 at 14:22
  • But if you were referring particularly to me because of the downvote you've got it wasn't me, I don't even like the get/set convention, I prefer C#'s hidden getter/setters. I'm just lazy like that. – Tomáš Zato Mar 9 '15 at 14:26
  • Yes, I saw that demo the other day, mind = blown. And no, I was not thinking that you downvoted. And yes, C# rules! – Mike Nakis Mar 9 '15 at 14:30
  • 1
    @BartvanIngenSchenau Your comment doesn't define anything to reason with or hold behind any evidence. It should be kept in mind that opinion on this site should be rational as much as it can get - and the guys answering here do post sufficiently rational opinions: "I do it that way because..." - which directly answers my question what to do and why. Specifically on StackExchange you might have a problem to wrap your mind around the fact that not everything is binary. But that's exactly why multiple answers can exist and be voted on. And often the first isn't the best - opinions... – Tomáš Zato Mar 9 '15 at 16:40
5

public final is OK in my book when you're implementing something that's just a data container. Making all the fields public final makes it clear that once the object is constructed, all the fields are available and there'll be no funny business going on behind the scenes (lazy initialization, computed values, values retrieved from I/O or whatever.)

The usual reasoning behind getters is that some day you might need your object to be a little "smarter". But you've already committed to using an enum, which presupposes that all the data is statically available and that your objects have value semantics. I'd bet that if you ever need to undo decision to use public final fields, an enum will probably no longer be right choice either.

The one time getters are absolutely necessary is when the class you're writing is part of the public API of a publicly available library, because you want to maintain binary compatibility at all costs. You don't want to introduce a backwards-incompatible change for something as trivial as changing a getter.

  • And how can public static MyType change and public MyType getSomething not? Several people point this out as important but I do not really get it. – Tomáš Zato Mar 9 '15 at 14:42
  • @TomášZato Not sure I understand what you're asking. – Doval Mar 9 '15 at 14:44
  • @TomášZato consider the refactoring you would need to do if you wanted to change the type of default_val from Object to, say, another String. You've changed your implementation details and since they are exposed, you would have to change everything that uses them. If it was a method, you could make the contract for that method be the same. – user40980 Mar 9 '15 at 14:49
  • @MichaelT the refactoring is not that much, really. On IntelliJ IDEA I can just right click on the field and select Refactor -> Encapsulate fields... which will turn the field private, add a getter, and refactor all code that used to access the field to use the getter instead. So we'd both be at the exact same spot: changing the type of the private field and the way the getter converts it to the old type before returning it. – Mike Nakis Mar 9 '15 at 15:37
  • 1
    @MikeNakis That is easy when you have the entire code base. It is a bit more challenging when you are working on a library that is used by a dozen other teams and don't have access to their source code. In such cases, it is necessary to do non-breaking changes to the libraries so applications you don't know about don't break with an upgrade. – user40980 Mar 9 '15 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.