string
password
char[]

Why is char[] preferred over String for passwords?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Java developers are often told to store passwords in char[] instead of String. The advice is not about syntax style. It is about reducing how long sensitive data stays readable in memory and how easily that data can be copied or exposed.

Why String Is a Poor Container for Secrets

A String is immutable. Once created, its characters cannot be changed. That makes strings convenient for general programming, but it is a bad property for passwords because you cannot actively erase the contents after authentication finishes.

If a password is stored in a String, the text stays in memory until the garbage collector eventually reclaims that object. You do not control when that happens. During that time, the value can appear in heap dumps, debugger inspections, crash reports, or accidental logging.

A char[] is mutable, so code can overwrite the characters immediately after use. That does not make the password magically safe, but it shortens the exposure window.

What char[] Lets You Do

The main advantage is explicit cleanup. After validating the password, you can replace each character with a neutral value.

java
1import java.util.Arrays;
2
3public class PasswordCheck {
4    public static boolean authenticate(char[] password) {
5        char[] expected = new char[] {'s', '3', 'c', 'r', 'e', 't'};
6        boolean matches = Arrays.equals(password, expected);
7        Arrays.fill(expected, '\0');
8        return matches;
9    }
10
11    public static void main(String[] args) {
12        char[] password = new char[] {'s', '3', 'c', 'r', 'e', 't'};
13
14        try {
15            System.out.println(authenticate(password));
16        } finally {
17            Arrays.fill(password, '\0');
18        }
19    }
20}

The important line is Arrays.fill(password, '\0'). With a String, there is no equivalent operation.

A Common Real-World Pattern

Swing uses this idea directly. JPasswordField returns char[] from getPassword() instead of returning a String.

java
1import java.util.Arrays;
2import javax.swing.JPasswordField;
3
4public class PasswordFieldExample {
5    public static void main(String[] args) {
6        JPasswordField field = new JPasswordField();
7        field.setText("topsecret");
8
9        char[] password = field.getPassword();
10        try {
11            System.out.println("Length: " + password.length);
12        } finally {
13            Arrays.fill(password, '\0');
14        }
15    }
16}

That API design exists for a reason: UI frameworks do not want to force secret input into an immutable string.

Security Benefit and Its Limits

Using char[] is a defensive improvement, not a full security system. The password may still be copied internally by libraries, converted into bytes for hashing, or captured elsewhere in the program. If you later do new String(password), you lose the benefit because you create another immutable copy.

It is also worth being precise about the risk. The problem is not that every String goes into the string pool. Passwords read from input are usually ordinary heap objects, not interned literals. The real issue is immutability and uncontrolled lifetime, not automatic interning.

Better Workflow for Password Handling

A reasonable flow in Java looks like this:

  1. Read the password into char[].
  2. Hash or verify it immediately.
  3. Clear the array in a finally block.
  4. Avoid converting it to String unless an API leaves no alternative.

Here is a simple example using MessageDigest after converting to bytes as late as possible:

java
1import java.nio.charset.StandardCharsets;
2import java.security.MessageDigest;
3import java.util.Arrays;
4
5public class PasswordHash {
6    public static byte[] sha256(char[] password) throws Exception {
7        byte[] bytes = new String(password).getBytes(StandardCharsets.UTF_8);
8        try {
9            return MessageDigest.getInstance("SHA-256").digest(bytes);
10        } finally {
11            Arrays.fill(bytes, (byte) 0);
12        }
13    }
14}

This example still creates a temporary String, so it is not ideal. It shows why secret-handling APIs often accept char[] directly when possible.

Common Pitfalls

Developers often switch to char[] but then immediately print it, log it, or convert it into String for convenience. That defeats the purpose.

Another common mistake is forgetting cleanup when exceptions occur. If you only clear the array on the success path, the password remains in memory during the error path, which is exactly where debugging tools and dumps are most likely.

Finally, do not oversell the rule. char[] reduces exposure, but secure password handling still depends on hashing, transport security, careful logging, and avoiding unnecessary copies.

Summary

  • 'String is immutable, so secret text cannot be erased after use.'
  • 'char[] can be overwritten, which shortens how long a password remains readable in memory.'
  • The main benefit is lifecycle control, not performance.
  • Converting a password back to String removes most of the advantage.
  • Clear password arrays in a finally block so cleanup also happens during failures.

Course illustration
Course illustration

All Rights Reserved.