1

from Java 9 onwards List.of() is available to create an Immutable list. How we can implement the same in versions before that (ex: java8) ?

According to the answer to this question Collections.unmodifiableList()

creates an unmodifiable view and It is not immutable because it changes if you're changing the original.

List.of() on the other hand, creates an immutable copy. Changing the original list will not affect it.

  • 2
    Using [Guava](https://guava.dev/releases/23.0/api/docs/com/google/common/collect/ImmutableList.html) is one option. – Robby Cornelissen May 06 '21 at 05:12
  • Use `new ArrayList` to copy then wrap in `Collections.unmodifiableList()`. You can also use `Arrays.asList` if you any to wrap varargs. – Boris the Spider May 06 '21 at 05:16
  • 2
    `List.of` doesn't create an immutable copy of another list... It creates an immutable list that has the elements you gave it. Did you confuse it with `List.copyOf`? – Sweeper May 06 '21 at 05:17
  • Honestly there's no exact equivalent. `List.of` creates an `ImmutableCollections.ListN` which actually has quite a bit of functionality in what it checks for and allows. It's also backed by an array for efficiency. Probably the closest simple replacement is `Stream.of().collect(toList())` – sprinter May 06 '21 at 05:25

2 Answers2

4

Try this.

@SafeVarargs
public static <T> List<T> listOf(T... elements) {
    List<T> list = new ArrayList<>();
    for (T e : elements)
        list.add(e);
    return Collections.unmodifiableList(list);
}

and

System.out.println(listOf(1, 2, 3));

String[] array = {"A", "B", "C"};
List<String> list = listOf(array);
array[0] = "zero";
System.out.println(list);

list.add("D");   // <- throws UnsupportedOperationException
System.out.println(list);

output:

[1, 2, 3]
[A, B, C]
1

If you really meant List#of methods, read the correct Answer by saka1029. If you actually meant List#copyOf, read this Answer.

Instantiate fresh new list before calling Collections.unmodifiableList

You are correct about Collections.unmodifiableList returning an object that is merely a view onto the original. So if the original changes, so too does the not-so-unmodifiable list.

The solution is simple: Copy the list into a new fresh list before passing to Collections.unmodifiableList.

List< Whatever > tempList = new ArrayList<>( myOriginalList ) ;  // Passing a collection to constructor of `ArrayList` creates an entirely new fresh list copied from the original.
List< Whatever > unmodifiableList = Collections.unmodifiableList( tempList ) ;

Be sure you never expose that tempList to any other code, so its contents are never manipulated. Or, better yet, use a single-line to make such sharing impossible.

List< Whatever > unmodifiableList = Collections.unmodifiableList( new ArrayList<>( myOriginalList ) ) ;

Being strict

To truly replicate the behavior of List#copyOf, you would check to see if the original list is already unmodifiable. If so, no action is taken. The original list is returned as the result of the method call. Quoting the Javadoc:

If the given Collection is an unmodifiable List, calling copyOf will generally not create a copy.

You should also do some null checks. Quoting the Javadoc:

The given Collection must not be null, and it must not contain any null elements.


Lastly, I will add a friendly suggestion that you consider upgrading past Java 8. Many wonderful new features have been added in the intervening years. Currently Java 16 is the latest release, with Java 17 this fall (2021-09-14) likely to be designated an LTS version.

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154