I have created an immutable class with a date field. How do I ensure that even the date field is immutable, since even if you make date field final you can still assign a different value to it later?
In your getDate()
method, return a new Date()
instance, instead of the same instance.
public Date getDate() {
// Not correct.
return this.date; // This will make your class mutable.
// Instead use,
return new Date(this.date.getTime()); // This will make sure your date field cannot be changed.
}
Other Answers are correct that in showing strategies for fixing values within your objects.
Let me also recommend that you use the modern java.time classes rather than the terrible legacy classes. In place of Date
, use Instant
. In place of Calendar
, use ZonedDateTime
.
The java.time classes are designed as immutable objects. Methods such as plus…
, minus…
, to…
, and with
all produce a fresh object, leaving the original intact. The classes carry no setter methods.
Bonus tip: In your own immutable classes, you may find it useful to follow the method naming patterns established by the java.time classes.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
You can clone date object so that it cannot be modified
public Date getDate (){
return (Date) this.date.clone ();
}
Here is the simple example of immutable
class in Java
public final class Employee{
final String pancardNumber;
public Employee(String pancardNumber){
this.pancardNumber=pancardNumber;
}
public String getPancardNumber(){
return pancardNumber;
}
}
The above class is immutable because:
These points makes this class as immutable. In case of Date
attribute, you can use constructor to set your date with every new object and import org.joda.time.DateTime
class. This is a better version than the java.util.Date
because it is immutable. Using a java.util.Date would be dangerous as it is a mutable class and we can’t control the calling thread (which might modify it). Here is example.
public final class Bill {
private final int amount;
private final DateTime dateTime;
public Bill(int amount, DateTime dateTime) {
this.amount = amount;
this.dateTime = dateTime;
}
public int getAmount() {
return amount;
}
public DateTime getDateTime() {
return dateTime;
}
}
This is an example of a Bean(Class) with an immutable HAS-A Date Object.
import java.util.Date;
public class MyBean {
private Date date; // Immutable Date Step 1 Make Private
public MyBean(Date date)
{
// Immutable Date Step 2 If Set through Constructor then get a specialised (sub class) Date.
this.date= getImmutableDate(date); // THIS METHOD RETURNS AN IMMUTABLE DATE
}
public MyBean(){} // Allow Default Constructor
public Date getDate() {
return date;
}
// Immutable Date Step 3- Allow setting of date only once!!
public void setDate(Date date) {
if(this.date==null)
{
this.date= getImmutableDate(date);
}
}
/* Override all Setter methods of Date class. So even if user gets reference of Date Object it is not the original date object
* it would be a modified date object whose all setter methods do nothing*/
private Date getImmutableDate(Date date)
{
/* This is an Anonymous Inner Class that extends java.util.Date class, it overrides all the setter methods
* making the date object IMMUTABLE( i.e setXXX has no effect)
* */
date =new Date(date.getTime()){
private static final long serialVersionUID = 1L;
@Override
public void setYear(int year) {}
@Override
public void setMonth(int month) {}
@Override
public void setDate(int date) {}
@Override
public void setHours(int hours) {}
@Override
public void setMinutes(int minutes) {}
@Override
public void setSeconds(int seconds) {}
@Override
public void setTime(long time) {}
};
return date;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With