3

Immutable Class with List

package com.text.immutable;

import java.util.Collections;
import java.util.List;

// An immutable class Student
public final class Student 
{ 
    final String name; 
    final int regNo; 
    final List<String> courses;  // want to make Immutable 

    public Student(String name, int regNo, List<String> courses) 
    { 
        this.name = name; 
        this.regNo = regNo; 
        this.courses = Collections.unmodifiableList(courses);
    } 
    public String getName() 
    { 
        return name; 
    } 
    public int getRegNo() 
    { 
        return regNo; 
    } 

    public List<String> getCourses() {
        return courses;
    }
} 

Testing Immutable Class to Break Immutability

package com.text.immutable;

import java.util.ArrayList;
import java.util.List;

class ImmutablityTest 
{ 
    public static void main(String args[]) 
    { 
        List<String> courses = new ArrayList<String>();
        courses.add("java");
        courses.add("spring");
        courses.add("hibernate");
        courses.add("rest");

        Student s = new Student("ABC", 101, courses); 

        System.out.println("Before Update List");
        System.out.println(s.getName()); 
        System.out.println(s.getRegNo()); 
        System.out.println(s.getCourses());
        courses.add("Hibernate"); // Able to Change which affect final OutCome
        //s.getCourses().add("SpringBoot"); // giving Exception in thread "main" java.lang.UnsupportedOperationException

        System.out.println("After Update List");
        System.out.println(s.getName()); 
        System.out.println(s.getRegNo()); 
        System.out.println(s.getCourses());

    } 
} 

Output is

Before Update List
ABC
101
[java, spring, hibernate, rest]
After Update List
ABC
101
[java, spring, hibernate, rest, Hibernate]

why and how this new Course element added into the List as its from Client Side can be added up any time so how we can fix this issue as this immutable class should not allow to modifying after once created

2
  • 2
    Clone the List, when setting it. Commented Oct 21, 2019 at 8:02
  • 2
    i'm always mixing them up - so your question is very reasonable +1 Commented Oct 21, 2019 at 8:19

4 Answers 4

4

this.courses = Collections.unmodifiableList(courses);

That creates, as the name says, an unmodifiable list. But that is just a view on the original list. Thus changes to that original list become visible in your "unmodifiable" view.

When in doubt: clone your list, like:

this.courses = new ArrayList<>(courses);

And then ensure that your getter does:

return Collections.unmodifiableList(courses);
Sign up to request clarification or add additional context in comments.

3 Comments

yes - it has to be unmodifiable - not immutable ^_^ +1
this.courses = Collections.unmodifiableList(new ArrayList<>(courses)); should also be suffice
Thanks @GhostCat yours also working but Koziolek also working which one is better and proper solution
2

Not the best in context of memory, but works:


// An immutable class Student
public final class Student 
{ 
    final String name; 
    final int regNo; 
    final List<String> courses;  // want to make Immutable 

    public Student(String name, int regNo, List<String> courses) 
    { 
        this.name = name; 
        this.regNo = regNo; 
        this.courses = new ArrayList(courses);
    } 
    public String getName() 
    { 
        return name; 
    } 
    public int getRegNo() 
    { 
        return regNo; 
    } 

    public List<String> getCourses() {
        return new ArrayList(courses);
    }
} 

On input (in constructor) you create copy of list and on output (in getter) you create copy.

1 Comment

Thanks @Koziolek yours also working but GhostCat also working which one is better and proper solution
1

read about immutableLists and you'll find that an Immutable and Unmodifiable Are Not the Same.

I guess (from your question) you are expecting an unmodifiable list which you simply don't create...

see this answer for a proper solution

Comments

0

With Collections.unmodifiableList, it creates a wrapper around the original list and that wrapper object is unmodifiable. The original list can still be updated.

So, in order for the List<String> courses list to be immutable, you can use Apache collection common library.

List<String> immutableList = com.google.common.collect.ImmutableList.of("Geeks", "For","Geeks");

ImmutableList has overridden the List.add method to always throw exception java.lang.UnsupportedOperationException


Second alternative is to create the list inside the constructor itself.

public Student(String name, int regNo,  String... args) 
{ 
    this.name = name; 
    this.regNo = regNo; 
    courses = (List)Arrays.asList(args);

}

And call it like this :

 Student s = new Student("ABC", 101, "a","a","a","a"); 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.