I was going through this tutorial and found the following code:
// ... enum constants ...
private final double mass; // in kilograms
private final double radius; // in meters
// ... enum constructor ...
private double mass() { return mass; }
private double radius() { return radius; }
Why does it define the mass
and radius
methods? Both variables and methods are private, so what purpose does it serve?
More generally, in what cases it is helpful to define a method with the same name and same access modifier as a variable?
Edit: I am aware of getters and setters. Firstly, the methods are NOT named getMass()
and getRadius()
as usual for getters, rather they have the exact same name as the properties. Secondly, I specifically mentioned that I am confused because both the properties and the methods are private. I don't see how this is a duplicate of this one.
get
?The community, and this notably includes the JDK itself, is confused about how to write a getter. The majority write a get prefix but there is a signficant minority that does not.
This is a bad idea; get
is the name of the thing as per the vast, vast majority of java programmers (they are called 'getters' after all!), and get
has pragmatic advantages: They clearly identify "this method retrieves a property, it has no side effects other than potentially some caching shenanigans, and represents the state as it is now". It also means you can type get
and hit auto-complete in your editor and see them all.
However, the record
feature auto-generates getter-like constructs for you and does not include the get
prefix. Apparently a mistake, but OpenJDK does not think so and continues to defend the choice. Not that it matters at this point; with the feature released out of preview the cost of changing it now is far higher than the damage done by failing to add those get prefixes. Point is: With records now part of standard java, the confusion about whether getters start with get
or not is complete.
So, it's just a choice. Some folks like writing their getters with get
in front.
It's varied:
You can write method handles, you cannot write field handles. If I want to write the notion "Given an instance of X, turn it into the value of this property of X", I can simply write X::getX
, for example in someListOfX.map().stream(X::getX)....
. There is no such syntax for fields. Thus, having the method there means you can write this. Even if no such code is in there right now, 'YAGNI' is just a rule of thumb; if you know it is highly likely that you'll need it, or it feels right for the API you are designing, you should add such things. Or at least, one could plausibly think one should.
If many places do the job of 'access property foo of myself', and you are thinking that perhaps in the future you want to e.g. add a logging line, or some caching stuff, to that job, then, for the same reason you don't want to repeat "someTrickyConstantValue"
85 times throughout a single source file (you'd want to do private static final String SOME_DESCRIPTOR = "someTrickyConstantValue";
and use that constant instead), you'd want all such accesses to go through a single method, so that if later you want to add logging, caching, normalizing, or whatever, you can do that in one place.
It somewhat indemnifies you to later change. If later on one notices that the field can actually go away and be live calculated, then you'd have to change all code if all code uses a field access. Now, you don't. For example, imagine we go from this:
enum Rank {
SPADES("black"), HEARTS("red"), CLUBS("black"), DIAMONDS("red");
... infra for having a field named 'color'.
private String color() { return color; }
}
to:
enum Rank {
SPADES, HEARTS, CLUBS, DIAMONDS;
private String color() {
return switch (this) {
case SPADES, CLUBS -> "black";
case HEARTS, DIAMONDS -> "red";
};
}
}
Then that can be done without having to change any calling code at all... if you had that method there.
These are all somewhat esoteric. They don't have to be fantastic reasons. Just.. good enough to plausibly explain why someone might want to do this.