Java transient keyword example

The Java transient keyword is used on class attributes/variables to indicate that serialization process of such class should ignore such variables while creating a persistent byte stream for any instance of that class.

A transient variable is a variable that can not be serialized. According to Java Language Specification [jls-8.3.1.3] – “Variables may be marked transient to indicate that they are not part of the persistent state of an object.”

In this post, I will discussing various concepts involved around usage of transient keyword in context of serialization.

Table of Contents

1. What is transient keyword in Java?
2. When should we use transient keyword in java?
3. Usage of transient with final keyword
4. Case study: How does a HashMap use transient?
5. Summary Notes

1. What is Java transient keyword

The modifier transient in java can be applied to field members of a class to turn off serialization on these field members. Every field marked as transient will not be serialized. You use the transient keyword to indicate to the java virtual machine that the transient variable is not part of the persistent state of an object.

Let’s write an very basic example to understand what exactly above analogy means. I will create an Employee class and will define 3 attributes i.e. firstName, lastName and confidentialInfo. We do not want to store/save “confidentialInfo” for some purpose so we will mark the field as “transient“.

class Employee implements Serializable
{
   private String           firstName;
   private String           lastName;
   private transient String confidentialInfo;

   //Setters and Getters
}

Now let’s serialize an instance of Employee class.

try
{
   ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("empInfo.ser"));
   Employee emp = new Employee();
   emp.setFirstName("Lokesh");
   emp.setLastName("Gupta");
   emp.setConfidentialInfo("password");
   //Serialize the object
   oos.writeObject(emp);
   oos.close();
} catch (Exception e)
{
   System.out.println(e);
}

Now let’s de-serialize back into java object, and verify if “confidentialInfo” was saved or not?

try
{
   ObjectInputStream ooi = new ObjectInputStream(new FileInputStream("empInfo.ser"));
   //Read the object back
   Employee readEmpInfo = (Employee) ooi.readObject();
   System.out.println(readEmpInfo.getFirstName());
   System.out.println(readEmpInfo.getLastName());
   System.out.println(readEmpInfo.getConfidentialInfo());
   ooi.close();
} catch (Exception e)
{
   System.out.println(e);
}

Program Output.

Lokesh
Gupta
null

Clearly, “confidentialInfo” was not saved to persistent state while serialization and that’s exactly why we use “transient” keyword in java.

2. When should we use transient keyword in java?

Now we have a very knowledge of “transient” keyword. Let’s expand out understanding by identifying the situations where you will need the use of transient keyword.

  1. First and very logical case would be where you may have fields that are derived/calculated from other fields within instance of class. They should be calculated programmatically everytime rather than having the state be persisted via serialization. An example could be time-stamp based value; such as age of a person OR duration between a timestamp and current timestamp. In both cases, you would be calculating value of variable based on current system time rather than when the instance was serialized.
  2. Second logical example can be any secure information which should not leak outside the JVM in any form (either in database OR byte stream).
  3. Another example could be fields which are not marked as “Serializable” inside JDK or application code. Classes which do not implement Serializable interface and are referenced within any serializable class, cannot be serialized; and will throw “java.io.NotSerializableException” exception. These non-serializable references should be marked “transient” before serializing the main class.
  4. And lastly, there are times when it simply doesn’t make sense to serialize some fields. Period. For example, In any class if you have added a logger reference, then what’s use of serializing that logger instance. Absolutely no use. You serialize the information which represent the state of instance, logically. Loggers never share the state of an instance. They are just utilities for programming/debugging purpose. Similar example can be reference of a Thread class. Threads represent a state of a process at any given point of time, and there is no use to store thread state with your instance; simply because they do not constitute the state of your class’s instance.

Above four usecases are when you should use the keyword “transient” with reference variables. If you have some more logical cases where “transient” can be used; please share with me and I will update that here in list so that everybody can benefit from your knowledge.

Read More : A min guide for implementing serializable interface

3. Transient with final

I am talking about use of transient with final keyword specifically because it behaves differently in different situations which is not generally the case with other keywords in java.

For making this concept practical, I have modified the Employee class as below:

private String           firstName;
private String           lastName;
//final field 1
public final transient String confidentialInfo = "password";
//final field 2
public final transient Logger logger = Logger.getLogger("demo");

Now when I again run the serialization (write/read) again, below is the output:

Program output.

Lokesh
Gupta
password
null

This is strange. We have marked the “confidentialInfo” to transient; and still the field was serialized. For similar declaration, logger was not serialized. Why?

Reason is that whenever any final field/reference is evaluated as “constant expression“, it is serialized by JVM ignoring the presence of transient keyword.

In above example, value “password” is a constant expression and instance of logger “demo” is reference. So by rule, confidentialInfo was persisted where as logger was not.

Are you thinking, what if I remove “transient” from both fields? Well, then fields implementing Serializable references will persist otherwise not. So, if you remove transient in above code, String (which implements Serializable) will be persisted; where as Logger (which does NOT implements Serializable) will not be persisted AND “java.io.NotSerializableException” will be thrown.

If you want to persist the state of non-serializable fields then use readObject() and writeObject() methods. writeObject()/readObject() are usually chained into serialization/deserialization mechanisms internally and thus called automatically.

Read More : SerialVersionUID in java and related fast facts

4. Case study : How does a HashMap use transient keyword?

So far, we have been talking about concepts related to “transient” keyword which are mostly theoretical in nature. Let’s understand the proper use of “transient” which is used inside HashMap class very logically. It will give you better idea about real life usage of transient keyword in java.

Before understanding the solution which has been created using transient, let’s first identify the problem itself.

HashMap is used to store key-value pairs, we all know that. And we also know that location of keys inside HashMap is calculated based on hash code obtained for instance of key. Now when we serialize a HashMap that means all keys inside HashMap and all values respective to key’s will also be serialized. After serialization, when we de-serialize the HashMap instance then all key instances will also be deserialized. We know that during this serialization/deserialization process, there may be loss of information (used to calculate hashcode) as well as most important is it is a NEW INSTANCE itself.

In java, any two instances (even of same class) can not have same hashcode. This is a big problem because the location where keys should be placed according to new hashcodes, are not in there correct positions. When retrieving the value of a key, you will be referring to the wrong index in this new HashMap.

Read More : Working with hashCode and equals methods in java

So, when a hash map is serialized, it means that the hash index, and hence the ordering of the table is no longer valid and should not be preserved. This is the problem statement.

Now look at how it is solved inside HashMap class. If go through the sourcecode of HashMap.java, you will find below declarations:

transient Entry           table[];
transient int             size;
transient int             modCount;
transient int             hashSeed;
private transient Set     entrySet;

All important fields have been marked at “transient” (all of them are actually calculated/change at runtime), so they are not part of serialized HashMap instance. To populate again this important information back, HashMap class uses writeObject() and readObject() methods as below:

private void writeObject(ObjectOutputStream objectoutputstream) throws IOException
{
  objectoutputstream.defaultWriteObject();

  if (table == EMPTY_TABLE)
    objectoutputstream.writeInt(roundUpToPowerOf2(threshold));
  else
    objectoutputstream.writeInt(table.length);

  objectoutputstream.writeInt(size);

  if (size > 0)
  {
    Map.Entry entry;
    for (Iterator iterator = entrySet0().iterator(); iterator.hasNext(); objectoutputstream.writeObject(entry.getValue()))
    {
      entry = (Map.Entry) iterator.next();
      objectoutputstream.writeObject(entry.getKey());
    }
  }
}

private void readObject(ObjectInputStream objectinputstream) throws IOException, ClassNotFoundException
{
  objectinputstream.defaultReadObject();

  if (loadFactor <= 0.0F || Float.isNaN(loadFactor))
    throw new InvalidObjectException((new StringBuilder())
    .append("Illegal load factor: ").append(loadFactor).toString());

  table = (Entry[]) EMPTY_TABLE;
  objectinputstream.readInt();

  int i = objectinputstream.readInt();
  if (i < 0)
    throw new InvalidObjectException((new StringBuilder()).append("Illegal mappings count: ").append(i).toString());
  int j = (int) Math.min((float) i * Math.min(1.0F / loadFactor, 4F), 1.073742E+009F);
  if (i > 0)
    inflateTable(j);
  else
    threshold = j;

  init();

  for (int k = 0; k < i; k++)
  {
    Object obj = objectinputstream.readObject();
    Object obj1 = objectinputstream.readObject();
    putForCreate(obj, obj1);
  }
}

With above code, HashMap still let the non-transient fields to be treated as they would normally do, but they wrote the stored key-value pairs at the end of the byte array one after the other. While de-serializing, it let the non-transient variables to be handled by default de-serialization process and then read the key-value pairs one by one. For each key the hash and the index is calculated again and is inserted to the correct position in the table so that it can be retrieved again without any error.

Above use of transient keyword was a very good example of proper usecase. You should keep remember it and mention it whenever it is asked in your next java interview question.

Related Post: How HashMap works in Java?

5. Summary Notes

  1. The modifier transient can be applied to field members of a class to turn off serialization on these field members.
  2. You can use transient keyword in classes with fields which needs to be secured or calculated on existing state fields. And use it when it simply doesn’t make sense to serialize those fields such as loggers and threads.
  3. Serialization does not care about access modifiers such as private; all non-transient fields are considered part of an object’s persistent state and are eligible for persistence.
  4. Whenever any final field/reference is evaluated as “constant expression”, it is serialized by JVM ignoring the presence of transient keyword.
  5. A good usecase of transient keyword in java is HashMap class.

That’s all from my side for “transient” keyword. If you want to add something in this post, please do let me know via comments. I will be happy to expand this post.

If you want to learn more concepts like this in future, I will suggest you to join my mailing list/ OR follow me on Google Plus/Facebook or Twitter. I do post interesting links other than howtodoinjava.com in my social profiles.

Happy Learning !!

References:

http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.3
http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html
http://docs.oracle.com/javase/specs/jls/se5.0/html/expressions.html#15.28

Leave a Reply

5 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial