Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getter and Setters in Java

Is it a good practice to make some data processing/validation in getters and setters? In wikipedia here there are 2 examples:

  • setDate method stores java.util.Date date in 3 separate private fields like year, month, day
  • getAmount method concatenate 2 fields number and currency and return something like "100 USD". And maybe amount field itself does not exist at all and getAmount is just a calculation method.

Are these good examples or it is better to avoid it? If it is better to avoid it, how can I implement these 2 examples above in a better way?

UPDATE: Please, Do not take examples with date and etc serious. It is just an example, of course it can be stupid.

Real example which I had.

I have an external third party system and I have to make integration. This external system expect from me some data as class with getters and setters. I have to pass 2 fields there, id (something like 09df723987cd7 (let's say GUID)) and formattedID something like "objecttype/09df723987cd7". I cannot change this external system.

I want to implement it like

getId() {
  return id
}

getFormattedId() {
    return objectType + "/" + id;
}

objectType is another field in this class.

My Question: is it OK, or there is some more elegant way to implement it?

like image 378
Zlelik Avatar asked Sep 26 '16 12:09

Zlelik


2 Answers

The examples you provided are not good fit, at least not in the form and with the names you mentioned.

I'll try with some better examples:

Setters

You might want to use them for validation mostly. As an example setDate(Date d) could check the data is in a certain range, e.g. not more than 20 years into the future etc. (depends on your requirements).

Getters

If those contain more than simple logic they probably represent virtual properties, i.e. properties that don't have an underlying field but are calculated on the fly.

Let's take getAmount() for example: there might not be any field amount or the amount might be stored in cents (or smaller) for some reason (e.g. no precision issues). Thus getAmount() might look like this:

public double getAmount() {
  return amountInCents / 100.0;
}

Note that the name getAmount() might be misleading though, so you might be better off using a name like getAmountInUSD() or similar.

General

Using getters and setters in Java is adviceable in most cases since you'd be able to the following (list not complete):

  • add validation logic (to the setters)
  • add transformation logic (setters, getters) for virtual properties
  • define access, i.e. read-only would mean there is no public setter
  • use libraries that are based on the Java Beans specification (which requires the use of setters and getters)
  • decouple the client/caller of the getter/setter, i.e. if at some point you want to add validation having field access done via a setter would not require the client to change (unless validation errors would need to be handled) etc.
  • use setters and getters for debugging purposes, e.g. by putting a breakpoint at the method and have a look at the stack trace to see who called it (mentioned by dsp_user)
like image 135
Thomas Avatar answered Oct 08 '22 03:10

Thomas


Anecdotes with setters and getters

My point? Like anything in this world, it's not a black-and-white clear cut what is the best way to use getters and setters.


Setterless classes and Builder pattern

Sometimes a class has heaps of properties (impractical to design a constructor taking all of them, and then if you do it anyway it is excruciating painful to use). Supplementary, many times such classes should be immutable after construction (so no public setters).

A Builder pattern with a Fluent interface gets the things... well... flowing

To validate or not to validate at setting time ?

For most of the cases, it is Ok to perform a validation at the setters level. However, it is not always wise to do it.

For example, there are cases in which the object can "transition" through invalid states and reach a "valid and self consistent state" only after a sequence of calls in the setters.
For example: "A motorcycle without two wheels is not a valid motorcycle" doesn't mean that I cannot setFrontWheel(null) as a temporary stage in repairing my motorcycle... design by contract be damn'd, I'll just call validateMe at the end and be done with it.

Multi-setters

If you need to perform validation on setting and certain combination of values don't make sense, use a multi-setter:

void setDate(int y, int m, int day) {
  int maxDaysInMonth=0;
  switch(m) {
    case 1:
    case 3:
    ...
    case 11:
       maxDaysInMonth=31;
       break;
    case 2: // that's feb
       maxDaysInMonth=isLeap(y) ? 29 : 28;
       break;
    case 4:
    case 6:
    ...
       maxDaysInMonth=30;
       break;
    default: // only 12 months in the year
       throw something;
  }
  if(d>=maxDaysInMonth) {
    // you catch my drift, yeah?
  }
}

Getters:

  1. "computed getters" - like that "100 USD" - is not a property in itself, many would argue the method should be called "computeSomething" or "toSomeForm" (like "toString"), but... is just so convenient and easy to remember Rectangle.getCentreX

  2. "restricted getters" - like

    protected ArrayList listeners;
    // look-but-don't-touch getter
    public List getListeners() {
      return Collections.unmodifiableList(this.listeners):
    }
  1. "void returning getters" - when the values are to be returned (copied or placed) inside a destination provided as a parameter. Useful when you wants to deny direct access to the data member itself and to avoid creating copies of your inner data - also goes hand in hand with high performance requirements. E.g.
     class Rectangle {
        void getCentre(Point2D resultHere) {
          resultHere.set(minX+width/2, minY+height/2);
        }
        // and not
        // Point2D getCentre() {
        //   return new Point2D.Double(minX+width/2, minY+height/2);
        // }
        // because... performance.
     }
like image 21
Adrian Colomitchi Avatar answered Oct 08 '22 05:10

Adrian Colomitchi