Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a class immutable in java with date field in it?

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?

like image 962
Mona Dhar Avatar asked Aug 06 '15 04:08

Mona Dhar


5 Answers

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.
}
like image 95
Codebender Avatar answered Oct 14 '22 10:10

Codebender


java.time

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.


About java.time

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?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

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.

like image 24
Basil Bourque Avatar answered Oct 14 '22 10:10

Basil Bourque


You can clone date object so that it cannot be modified

public Date getDate (){
         return (Date) this.date.clone ();
}
like image 22
Saurabh Avatar answered Oct 14 '22 09:10

Saurabh


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:

  1. The instance variable of the class is final i.e. we cannot change the value of it after creating an object.
  2. The class is final so we cannot create the subclass.
  3. There is no setter methods i.e. we have no option to change the value of the instance variable.

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;
    }
}  
like image 41
Avinash Mishra Avatar answered Oct 14 '22 09:10

Avinash Mishra


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;
}

}

like image 20
Oliver Avatar answered Oct 14 '22 11:10

Oliver