by Chris Hermansen
Getters and setters are essential for retrieving and modifying external class variables. Setters update variable values, while getters read variable values.
Regular Java users are probably familiar with them. If you’re not, here’s what you need to know as we dive deeper into Apache Groovy. (If you haven’t installed Groovy yet, please read the intro to this series.)
The “get concept” (and the related “set concept”) appears in Java in a few different ways. One particular use is in the context of the JavaBean, in order to implement and enforce encapsulation. This works as follows:
- A Java class defines a field (also known as a property) as something known only within the class.
- If the class wants to expose the value of that field to programs using the class, then it provides a method to get the value of the property, called a “getter”
- If the class wants to allow the outside world to adjust the value of the class, then it provides a method to set the value of the property, called a “setter”
- By separating the details of storing the value from the access to that value by the outside world, the class is free to change the internal implementation details of the storage of the value.
Here’s an example. Imagine creating a class that represents a circle. Internally, that class could store the origin of the circle and its radius, and provide getters to return the value of the origin, the radius, the diameter, the area, and the circumference. Other programs using the class would be unaware that the current implementation only stores the origin and radius. If for some reason, the maintainer of the class decided to instead store the origin and the area, then there’s no external factor impeding that change.
Here’s the class:
1 import java.lang.*;
2 public class Groovy03a {
3 static public void main(String[] args) {
4 var c = new Circle(1.5d,1.7d,15d);
5 System.out.println("c area = " + c.getA());
6 System.out.println("c circumference = " + c.getC());
7 c.setA(100.0d);
8 System.out.println("c area = " + c.getA() + "; radius = " + c.getR());
9 }
10 }
11 class Circle {
12 private double x, y, r;
13 public Circle(double x, double y, double r) {
14 this.x = x;
15 this.y = y;
16 this.r = r;
17 }
18 public double getX() {
19 return this.x;
20 }
21 public double getY() {
22 return this.y;
23 }
24 public double getR() {
25 return this.r;
26 }
27 public double getA() {
28 return Math.PI * this.r * this.r;
29 }
30 public double getC() {
31 return 2.0d * Math.PI * this.r;
32 }
33 public void setX(double x) {
34 this.x = x;
35 }
36 public void setY(double y) {
37 this.y = y;
38 }
39 public void setR(double r) {
40 this.r = r;
41 }
42 public void setA(double a) {
43 this.r = Math.sqrt(a / Math.PI);
44 }
45 public void setC(double c) {
46 this.r = c / 2.0d / Math.PI;
47 }
48 }
Line four shows creating a circle centered on (1.5,1.7) with a radius of 15.0.
In lines five to six, use the getA()
and getC()
getter methods to find the area and radius of the circle.
In line seven use the setA()
setter method to set the area of the circle to 100.0. You can see on lines 42-44 that this is implemented by calculating the internally stored radius from the area provided.
Programmers who use integrated development environments (IDEs) like NetBeans or Eclipse count on their IDE to help with writing simple getters and setters. This means that they only end up writing the complicated ones (like getA()
, getC()
, setA()
and setC()
in the example above).
The Groovy programming language handles this slightly differently:
- Fields (or properties) of classes are by default private and default getters and setters are automatically generated
- The
c.a
on the right-hand side of an assignment statement is equivalent toc.getA()
. - The
c.a
on the left-hand side of an assignment statement is equivalent toc.putA(
value-on-the-right-hand-side)
. - The “manually created” getters and setters can also be accessed by the dot notation.
Here’s a similar example in Groovy, showing first the equivalence to Java (lines four-eight), then using dot notation (lines nine-12):
1 import java.lang.*;
2 public class Groovy03a {
3 static public void main(String[] args) {
4 def c = new Circle(1.5d,1.7d,15d)
5 println "c area = " + c.getA()
6 println "c circumference = " + c.getC()
7 c.setA(100.0d)
8 println "c area = " + c.getA() + "; radius = " + c.getR()
9 c.x = 2.3d
10 c.y = 1.9d
11 c.a = 225d
12 println "c.x ${c.x} c.y ${c.y} c.r ${c.r} c.a ${c.a} c.c ${c.c}"
13 }
14 }
15 class Circle {
16 double x, y, r;
17 public Circle(double x, double y, double r) {
18 this.x = x;
19 this.y = y;
20 this.r = r;
21 }
22 public double getA() {
23 return Math.PI * this.r * this.r;
24 }
25 public double getC() {
26 return 2.0d * Math.PI * this.r;
27 }
28 public void setA(double a) {
29 this.r = Math.sqrt(a / Math.PI);
30 }
31 public void setC(double c) {
32 this.r = c / 2.0d / Math.PI;
33 }
34 }
Note that there are no getters nor setters declared for the properties x
, y
, and r
. Running the above, you see:
$ groovy Groovy03a.groovy
c area = 706.8583470577034
c circumference = 94.24777960769379
c area = 99.99999999999999; radius = 5.641895835477563
c.x 2.3 c.y 1.9 c.r 8.462843753216344 c.a 224.99999999999997 c.c 53.173615527165474
$
Another appearance of getters and setters is in lists, maps and so forth:
1 import java.lang.*;
2 import java.util.ArrayList;
3 import java.util.HashMap;
4 public class Groovy03b {
5 static public void main(String[] args) {
6 var als = new ArrayList<String>();
7 als.add("Fee");
8 als.add("Fie");
9 als.add("Foe");
10 als.add("Fum");
11 System.out.println("als = " + als);
12 System.out.println("als[2] = " + als.get(2));
13 als.set(3, "Foo");
14 System.out.println("als = " + als);
15 }
16 }
To put elements initially into the ArrayList
, use the add() method, as on lines 7-10. Then you can use get()
and set()
to retrieve or set the value by list index. Similarly, for maps, you use get()
and set()
to retrieve or set the value by the key.
Compiling and running the above, you see:
$ java Groovy03b
als = [Fee, Fie, Foe, Fum]
als[2] = Foe
als = [Fee, Fie, Foe, Foo]
$
Groovy provides much cleaner syntactic support for these operations on lists and maps. Here’s some Groovy code that does the same thing:
1 def als = []
2 als << "Fee"
3 als << "Fie"
4 als << "Foe"
5 als << "Fum"
6 println "als = " + als
7 println "als[2] = " + als[2]
8 als[3] = "Foo"
9 println "als = " + als
Note here that you’re just creating a Groovy script, so no class definitions and other distractions like that.
In lines two to five, use the <<
operator which is overloaded to add()
.
In lines seven to eight you’re using the subscript notation [n]
which takes the place of get()
and set()
respectively when it’s on the right-hand side or left-hand side of the assignment statement.
Maps can also use subscript notation or they can reference a constant key using the dot notation. That is, map["a"]
and map.a
are equivalent.
Conclusion
Getters and setters are ubiquitous in one form or another throughout Java and Groovy, but the overhead associated with them in Groovy is much, much lower in Java.
This post is part of a series on Apache Groovy, stay tuned for more.
Photo by Jeff Sheldon on Unsplash
One response to “An essential guide to getters and setters in Apache Groovy”
[…] the last article in this series, you saw how Apache Groovy streamlines details related to getters and setters in all […]