00:00

transient Keyword in Java – Excluding Fields from Serialization

The transient keyword marks a field that must not be serialized. When an object is written with Java serialization, transient fields are skipped, and when it is read back they receive their default values (null, 0 or false).

It is used for sensitive data such as passwords, for values that can be recomputed, and for fields whose types cannot be serialized, such as connections, threads and loggers. This tutorial shows each case with runnable examples.

1. A Quick Look at Serialization

Serialization converts an object into a stream of bytes so it can be saved to a file, cached or sent over a network; deserialization rebuilds the object. A class opts in by implementing java.io.Serializable, and by default every non-static, non-transient field is written. transient is how you leave a field out.

2. Basic Example

TransientDemo.java
import java.io.*;

public class TransientDemo {
    static class User implements Serializable {
        private static final long serialVersionUID = 1L;
        String username;
        transient String password;   // never written to the stream
        transient int loginCount;    // primitive: restored as 0
        static String server = "eu-1"; // static: not part of the object at all

        User(String username, String password, int loginCount) {
            this.username = username; this.password = password; this.loginCount = loginCount;
        }
        public String toString() {
            return "User[username=" + username + ", password=" + password + ", loginCount=" + loginCount + "]";
        }
    }

    public static void main(String[] args) throws Exception {
        User before = new User("asha", "s3cret!", 42);
        System.out.println("Before: " + before);

        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(bytes)) {
            out.writeObject(before);
        }
        try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
            User after = (User) in.readObject();
            System.out.println("After:  " + after);
        }
    }
}
Output
Before: User[username=asha, password=s3cret!, loginCount=42]
After:  User[username=asha, password=null, loginCount=0]
  • username was serialized and restored.
  • password and loginCount were skipped and came back as null and 0.
  • static fields belong to the class, not the object, so they are never serialized whether or not they are transient.

3. When to Use transient

SituationExample fields
Sensitive data that must not leave memoryPasswords, tokens, keys
Derived values that can be recomputedCached totals, areas, hash codes
Types that are not serializableThread, Socket, database connections, streams, loggers
Runtime-only stateCaches, locks, listeners

4. Restoring transient Fields After Deserialization

Because transient fields come back with default values, restore them in a private readObject method, which the serialization mechanism calls automatically:

TransientRecompute.java
import java.io.*;

public class TransientRecompute {
    static class Rectangle implements Serializable {
        private static final long serialVersionUID = 1L;
        private final double width, height;
        private transient double area;   // derived value: cheap to recompute

        Rectangle(double width, double height) {
            this.width = width; this.height = height;
            this.area = width * height;
        }

        // Called during deserialization: restore the transient field
        private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
            in.defaultReadObject();
            area = width * height;
        }

        public String toString() { return width + " x " + height + " = " + area; }
    }

    public static void main(String[] args) throws Exception {
        Rectangle r = new Rectangle(4, 2.5);
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        try (ObjectOutputStream out = new ObjectOutputStream(bytes)) { out.writeObject(r); }
        try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes.toByteArray()))) {
            System.out.println("Restored: " + in.readObject());
        }
    }
}
Output
Restored: 4.0 x 2.5 = 10.0

Alternatively, initialise transient fields lazily on first use. Note that constructors and field initialisers of a Serializable class do not run during deserialization.

5. Avoiding NotSerializableException

If a serializable object holds a reference to a non-serializable object, serialization fails. Marking that field transient solves it:

TransientNonSerializable.java
import java.io.*;
import java.util.logging.Logger;

public class TransientNonSerializable {
    static class Connection { /* not Serializable */ }

    static class Session implements Serializable {
        private static final long serialVersionUID = 1L;
        String id = "S-1001";
        transient Connection connection = new Connection(); // would cause NotSerializableException
        transient Logger log = Logger.getLogger("session");
    }

    static class BadSession implements Serializable {
        private static final long serialVersionUID = 1L;
        String id = "S-1002";
        Connection connection = new Connection();            // not transient!
    }

    static void save(Object o) {
        try (ObjectOutputStream out = new ObjectOutputStream(new ByteArrayOutputStream())) {
            out.writeObject(o);
            System.out.println(o.getClass().getSimpleName() + ": serialized OK");
        } catch (IOException e) {
            System.out.println(o.getClass().getSimpleName() + ": " + e);
        }
    }

    public static void main(String[] args) {
        save(new Session());
        save(new BadSession());
    }
}
Output
Session: serialized OK
BadSession: java.io.NotSerializableException: TransientNonSerializable$Connection

6. Rules and Behaviour

  • transient applies only to fields, not to methods, classes or local variables.
  • It has an effect only for classes using Java serialization (Serializable). With Externalizable you write fields yourself, so the keyword is ignored.
  • final transient fields cannot be reassigned in readObject (without reflection), so they stay at their default value after deserialization. Avoid that combination.
  • Many JSON libraries respect transient too: Gson skips transient fields by default, and Jackson can be configured to (MapperFeature.PROPAGATE_TRANSIENT_MARKER).
  • In JPA, the @Transient annotation (not the keyword) excludes a field from database persistence.

7. transient vs static vs volatile

KeywordPurposeSerialized?
transientExclude an instance field from serializationNo
staticField belongs to the class, shared by all objectsNo (not part of the object)
volatileMake writes visible across threadsYes (unrelated to serialization)

8. Summary

  • transient fields are skipped during serialization and get default values on deserialization.
  • Use it for secrets, derived data, runtime state and non-serializable references.
  • Restore transient fields in readObject or lazily on first use.
  • Static fields are never serialized; volatile is about threads, not serialization.

Related Tutorials