It is up to the implementation to change the contents of the Java Collection. You won't know if you can change that Collection until you check the source code or try it out.
For example, in the javadoc of the List interface, it says:
UnsupportedOperationException --if add operation is not supported in this list
UnsupportedOperationException - if the add operation is not supported by this list
This is such a specification, so there is nothing you can do about it, but it is quite inconvenient for the caller. In this article, I'll show you how to tell the caller that "this collection is immutable."
https://www.gwtcenter.com/covariance-and-contravariance The content itself is almost written here. I found it useful in communicating the immutability of the Collection to the compiler, so I will delve into that part this time.
I'm using java11, but it works with java8 as well.
$ java --version
openjdk 11.0.8 2020-07-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.8+10)
Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.21.0, JRE 11 Mac OS X amd64-64-Bit Compressed References 20200715_677 (JIT enabled, AOT enabled)
OpenJ9 - 34cf4c075
OMR - 113e54219
JCL - 95bb504fbb based on jdk-11.0.8+10)
The java.util.Arrays # asList method returns a List, which cannot use add.
List<String> unmodifiableList = Arrays.asList("A", "B", "C");
unmodifiableList.add("d"); // UnsupportedOperationException
Set the variable's generics to ? Extends String
.
If you do so, all methods that take generics as arguments will result in a compilation error.
add
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
unmodifiableList.add("d"); // java:Incompatible type: java.lang.String? extends java.lang.String capture#Cannot be converted to 1
addAll
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
List<? extends String> anotherList = Arrays.asList("B");
unmodifiableList.addAll(anotherList); // java:Incompatible type: java.util.List<? extends java.lang.String capture#1>Java.util.Collection<? extends ? extends java.lang.String capture#2>Cannot be converted to
replaceAll
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
unmodifiableList.replaceAll(s -> s.replaceAll("C", "D"));
By the way, if you return the value as it is, the compilation error will not occur.
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
unmodifiableList.replaceAll(s -> s);
unmodifiableList.forEach(System.out::println);
It is possible to retrieve it as a String type.
get
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
String s = unmodifiableList.get(0);
System.out.println(s); // A
indexOf Methods that take Object type arguments, such as ʻindexOf`, can be used as is.
List<String> unmodifiableList = Arrays.asList("A", "B", "C");
int index = unmodifiableList.indexOf("B");
System.out.println(index); // 1
Basically, you can't remove ʻextends because you can't reassign it to a variable that doesn't use ʻextends
for generics.
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
List<String> list = unmodifiableList; // java:Incompatible type: java.util.List<? extends java.lang.String capture#1>Java.util.List<java.lang.String>Cannot be converted to
Since the reverse assignment is possible, it is also possible to use List <String
as the variable in the method andList <? Extends String>
as the return value.
List<String> unmodifiableList = Arrays.asList("A", "B", "C");
List<? extends String> list = unmodifiableList;
However, you can assign to variables that do not use generics.
List<? extends String> unmodifiableList = Arrays.asList("A", "B", "C");
List rowList = unmodifiableList;
rowList.add("D"); // UnsupportedOperationException
~~ raw type itself is an Unsupported Operation ~~ If you want to make a modifiable Collection such as ʻArrayList` immutable, you should properly Collections # unmodifiableList Wrap it in /Collections.html#unmodifiableList (java.util.List)) before doing so.
Extra characters will be added to the generics part, and it is used differently from the original purpose, so I think it is a thought to use it a lot. It's not without loopholes, so it's not all-purpose. But is it kinder than telling at runtime that add etc. can't be used? I think that, so I introduced it this time.