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

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

5 thoughts on “Java transient keyword example”

  1. Sir can you explain why transient key word does’t work with static/final keyword in serialisation ?

  2. “`
    public class Bean1 implements Serializable {

    /**
    *
    */
    private static final long serialVersionUID = -9098687921796988767L;

    private int field1;
    private int field2;
    private transient final int field3 = 456*432/123;
    public Bean1(int field1, int field2) {
    super();
    this.field1 = field1;
    this.field2 = field2;
    }
    public int getField1() {
    return field1;
    }
    public void setField1(int field1) {
    this.field1 = field1;
    }
    public int getField2() {
    return field2;
    }
    public void setField2(int field2) {
    this.field2 = field2;
    }
    public int getField3() {
    return field3;
    }
    @Override
    public String toString() {
    return “Bean1 [field1=” + field1 + “, field2=” + field2 + “]”;
    }

    }
    “`
    this is the bean I used to test your 4th point in summary

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

    “`
    Bean1 o = new Bean1(123, 234);
    String filename = “file.ser”;

    // Serialization
    try
    {
    //Saving of object in a file
    FileOutputStream file = new FileOutputStream(filename);
    ObjectOutputStream out = new ObjectOutputStream(file);

    // Method for serialization of object
    out.writeObject(o);

    out.close();
    file.close();

    System.out.println(“Object has been serialized”);

    }

    catch(IOException ex)
    {
    System.out.println(“IOException is caught”);
    }
    Bean1 object1 = null;

    // Deserialization
    try
    {
    // Reading the object from a file
    FileInputStream file = new FileInputStream(filename);
    ObjectInputStream in = new ObjectInputStream(file);

    // Method for deserialization of object
    object1 = (Bean1)in.readObject();

    in.close();
    file.close();

    System.out.println(“Object has been deserialized “);
    System.out.println(object1.toString());
    }

    catch(IOException ex)
    {
    System.out.println(“IOException is caught”);
    }

    catch(ClassNotFoundException ex)
    {
    System.out.println(“ClassNotFoundException is caught”);
    }

    “`
    this is the main method code
    “`

    Object has been serialized
    Object has been deserialized
    Bean1 [field1=123, field2=234]
    “`
    this is the output I got and it ignored the transient field even though it is final and has a constant expression.

    waiting for your reply
    Thank you.

    • Sorry
      Actually it is my mistake
      Eclipse didn’t included the transient field
      I now included and it is fine.
      Thank you, you’d done a great work

  3. HI Lokesh,

    Could you explain why it would be a problem during deserialisation as you mentioned there will be loss of information for calculating new hash code.hash code would be calculated based on he method that we override for that specific class right !! Wont the JVM use the same method to calculate the hash code for entires in hash map after deserialisation is done.Do you mean to tell for the scenario where hash code method is not over riden to calculate the hash code and object class code(hash code calculates based on internal memory representation )is applied..please clarify this

    • Yes, you are right. I am talking about custom implementation of hashCode() method which may include fields which do not take into consideration while serialization. e.g static fields or simply transient fields. If hashCode() is using these fields then after de-serialization they would not be available.
      If you have not overridden hashCode() method then hashCode is definitely going to be different, because in JVM no two instances can have same hashcode, right?

Comments are closed.

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.