14

Let's say I have a class Comment and I have a private field named commentDate which is a java.util.Date and with a getter named getCommentDate.

Why it's better to return a copy of that date ( return new Date(commentDate.getTime()) ) than simply returning that date...

How can a user change the object state of that Date since it's a getter, not a setter?

Sisyphus
  • 4,181
  • 1
  • 22
  • 15
spauny
  • 4,976
  • 9
  • 44
  • 61

8 Answers8

14

Since java.util.Date implements Cloneable you can easily clone the date, as:

public class DateTest {
    private Date date;

    public DateTest() {

    }

    public Date getDate() {
        return (Date) date.clone();
    }

    public void setDate(Date date) {
        this.date = (Date) date.clone();
    }       
}
Tapas Bose
  • 28,796
  • 74
  • 215
  • 331
  • 3
    What about if the date is a null value? – Calonthar Aug 19 '14 at 06:35
  • In JAVA 8 you can do the following: For GET method: return Optional.ofNullable(date).map(Date::getTime).map(Date::new).orElse(null); For SET method: this.date = Optional.ofNullable(date).map(Date::getTime).map(Date::new).orElse(null); – Khanh Tran Sep 14 '17 at 15:59
  • 1
    Why not to use directly a ternary operator? E.g. with get: return yourDate == null ? null : new Date(yourDate.getTime()); About cloning: https://stackoverflow.com/questions/7082553/java-util-date-clone-or-copy-to-not-expose-internal-reference – antcalvente Oct 18 '17 at 09:55
7

First off, please, please, please avoid using getters and setters as much as possible. If you have both of them for the same field you are almost certainly doing something wrong. I don't care what the Java gurus are telling you. They don't know what they're talking about. This is not how OO works. OO is not a make-work project to turn field accesses into method calls. That doesn't actually encapsulate anything.

That said: if you return the date itself, then the calling code has a reference to your date object, and can use its full interface. Since dates are mutable objects, the interface includes things that can change the object state. Since the reference is to your date, your date's state will get changed. It doesn't matter how the calling code got the date (i.e. "with a getter").

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • How can I access the fields without getter and setter? it's better to call them? < Comment.commentDate > – spauny Jun 28 '11 at 07:47
  • 5
    You **don't**. That's the point of OO. The person who uses a Comment instance is not supposed to know that there is a Date field. That person is not supposed to **need** to know this. The Comment class is supposed to expose an interface that consists of functions that **do useful things** with a Comment. – Karl Knechtel Jun 28 '11 at 07:51
  • 7
    Yeah. `printCommentDateWithGivenDateFormatToGivenFile()`, `convertCommentDateToXml()`, `compareToAnotherCommentAccordingToCommentDate()` etc. Very handy. – Tadeusz Kopec for Ukraine Jun 28 '11 at 08:00
  • 3
    Um, no. You just `write` a comment, and either pass the date format as a parameter or have already DI'd it. You don't convert the comment date by itself to XML; you almost certainly need the whole comment converted to XML. `compareToAnotherCommentAccordingToCommentDate(Comment other)` is more naturally spelled `predates(Comment other)`. Again, the calling code is not supposed to think of the Comment as something that has a date field; accordingly, the idea of method names that contain `CommentDate` is suspicious in and of itself. – Karl Knechtel Jun 28 '11 at 08:05
  • 1
    So the comment class needs to be able to handle XML serialization, JSON serialization, SQL serialization, displaying itself as a Swing widget, outputting itself into an HTML table, parsing its data from an HTML form all by itself? – Thilo Jun 28 '11 at 08:31
  • ... ? Serialization is something you do with data. If you really have data, then go ahead and use public fields. If you don't, then it doesn't make sense to expect some outside mechanism to serialize the thing that you have. At the very least, you need to be able to tell it what data to serialize. It is normal and useful for objects to contain references at runtime that shouldn't be serialized (to, say, resources that are created from scratch on each program run). – Karl Knechtel Jun 28 '11 at 18:08
5

How can a user change the object state of that Date since it's a getter, not a setter?

Easily:

Comment comment = new Comment();
comment.getCommentDate().setTime(0); // now it's January 1, 1970 00:00:00 GMT.
Tadeusz Kopec for Ukraine
  • 12,283
  • 6
  • 56
  • 83
2

Follow Tapas Bose example, we can do the following using JAVA 8 to handle NULL cases:

public class DateTest {
private Date date;

public DateTest() {

}

public Date getDate() {
    return Optional.ofNullable(date).map(Date::getTime).map(Date::new).orElse(null);
}

public void setDate(Date inputDate) {
    this.date= Optional.ofNullable(inputDate).map(Date::getTime).map(Date::new).orElse(null);
}}

Reference: Is there a way to copy Date object into another date Object without using a reference? (Nicolas Henneaux's answer)

Khanh Tran
  • 447
  • 6
  • 21
1

The user can't "replace" the instance provided by getCommentDate(). However, the user can invoke getCommentDate().setMonth(10) and thereby modifying the date. Thus, if this is a concern, I'd advise you to return a copy of the "original" instance.

sbrattla
  • 5,274
  • 3
  • 39
  • 63
1

Since java.util.Date is mutable, it could be changed via the getter like this:

getCommentDate().setYear(2011)

This will cause the commentDate on the comment to be changed to the year 2011. All other set methods on Date can be called as well off course, just an example.

wjans
  • 10,009
  • 5
  • 32
  • 43
0

Note: Do not return mutable objects via getters eg. date (before Java 8). It can always be reset by a rogue programmer. Lets say you write a program where social security benefits of an employee is calculated based on the years of work.

public class Employee {
// instance fields
private String name;
private String nickName;
private double salary;
private Date hireDay;

// constructor
Employee(String name, String aNickName, double aSalary, int aYear,
        int aMonth, int aDay) {
    this.name = name;
    nickName = aNickName;
    salary = aSalary;
    GregorianCalendar cal = new GregorianCalendar(aYear, aMonth - 1, aDay);
    hireDay = cal.getTime();
}
//needs to be corrected or improved  because date is a mutable object
public Date getHireDay() {
    return hireDay;
}

A hacker/bad programmer can reset the date using a setter

Employee john = new Employee("John", "Grant", 50000, 1989, 10, 1);
    Date d = john.getHireDay();

    // Original hire date is Oct 1, 1989
    System.out.println("Original hire date "+ d.getTime()));

    long tenYearsInMilliseconds = 10 * 365 * 24 * 60 * 60 * 1000L;
    long time = d.getTime();

    // Hire date after hacker modifies the code
    d.setTime(time - tenYearsInMilliseconds);
    System.out.println("Hacked hire date "+john.getHireDay().getTime()));
}

Instead..return a clone of the date method for Java 7 or use LocalDate Class for Java 8

 // for Java 7
public Date getHireDay() {
    return (Date)hireDay.clone();
}

//for Java 8
public LocalDate getHireDay() {
    return hireDay;
}
karto
  • 3,538
  • 8
  • 43
  • 68
0

In Java you are dealing with references. When you've a getter and returning your commentDate then you're in fact returning a reference to the object. That means that it is the same object like in your private field the caller can operate on due to reference returned by getter.

Fabian Barney
  • 14,219
  • 5
  • 40
  • 60
  • But if i set that date to another date (1970) and then I call my method again, the returning date it's now 1970? – spauny Jun 28 '11 at 07:49
  • Yes, of course. And when it is still the same object (i.e. you just called `setYear(70)`) then everybody got this date before through your getter sees 1970, too. That's because they all have references to the same object which you manipulated. And when anybody got the object through your getter and manipulates it then it also affects everybody else holding references to this object (including your class with a reference to it). This can be very nice but sometimes you've to be aware of cases where you do not want others to be able to manipulate "your" objects. – Fabian Barney Jun 28 '11 at 08:33
  • Then immutable data objects come into play, like @Andrzej Doyle stated in his comment above. These classes are designed to be immutable, so you do not have to care about others manipulating these kind of objects. – Fabian Barney Jun 28 '11 at 08:43