Programming/Java

[Java] Immutable Object

erinh 2024. 4. 1. 22:09
반응형

Immutable Object

: An object whose state cannot be modified after it is created

- Once an immutable object is instantiated, its internal state(the values of its fields) cannot be altered through any means.

1. Thread Safety

- In a multi-threaded envrionment, multiple threads can access an immutable object simultaneously without worrying about synchronization issues

2. Simplified Concurrency

- Since immutable objects cannot be modified, they can be safely shared among multiple threads without the ned for synchronization mechanisms such as locks or mutexes

- The simplifies concurrent programming and reduces the risk of race conditions

3. Caching and Reuse

- Immutable objects can be cached and reused freely because their state cannot change

- This can lead to performance improvements by avoiding unnecessary object creation

4. Easier Debugging

- Reduces the complexity of tracking down bugs related to unexpected state chanes

How to create an immutable object in Java

1. Make Fields Private and Final

- Declare all fields of the class as private and final to ensure that they cannot be modified once initalized

2. Do Not Provide Setter Methods

- Omit setter methods for the fields to prevent external modification of the object's state

3. Declare the Class as Final

- Make the class final to prevent subclassing, which could potentially introduce mutable behavior

// Example of mutable behavior

public class Person {
    private final String name;
    
    public Person (String name) {
    	this.name = name;
    }
    
    public String getName(){
    	return name;
    }
}

public class NewPerson extends Person {
	
    private String newName;
    
    public NewPerson(String name) {
    	super(name);
        newName = name;
    }
    
    public void setName(String name) {
    	this.newName = name;
    }
    
    public String getName() {	//override
    	return this.newName;
    }
 }
 
Person person = new NewPerson("Erin");
System.out.println(person.getName());		// Erin
 
NewPerson newPerson = (NewPerson) person;
newPerson.setName("wow");

System.out.println(person.getName());		// wow

4. Ensure Mutable Objects are Immutable or Safely Copied

- If the class contains references to mutable objects (such as collections), ensure that these objects are either immutable themselves or are safely copied to prevent external modification

public final class Person {
    private final String name;
    private final List<Job> jobs;
    
    public Person(String name, List<Job> jobs) {
    	this.name = name;
        this.jobs = copy(jobs);
    }
    
    public String getName() {	return name;	}
    
    public List<Job> getJobs() {	return copy(jobs);	}
    
    public List<Job> copy(List<Job> jobs) {
    	List<Job> cps = new ArrayList<Job>();
        jobs.forEach(o -> cps.add(new Job(o.title, o.salary)));
        return cps;
    }
 }

5. Create Defensive Copies if Necessary

- If the class exposes references to mutable object via getter methods, consider returning defensive copies of these objects to prevent clients from modifying the internal state

public final Class Person {
    private final String name;
    private final Job job;	// Job is mutable
    
    public Person(String name, Job job) {
    	this.name = name;
        this.job = new Job(job.title, job.salary);
    }
    
    public String getName() {
    	return name;
    }
    
    public String getJob() {
    	return new Job(job.title, job.salary);
    }
}

 

반응형