[Java] Adding an element to the Collection causes a compile error

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:

-Japanese

UnsupportedOperationException --if add operation is not supported in this list

-English

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."

References

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.

environment

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)

Main subject

Make an immutable list

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

Make the add method get a compile error

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);

Extracting the value

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

Reassignment

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;

A loophole called raw type

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.

Summary

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.

Recommended Posts

[Java] Adding an element to the Collection causes a compile error
I get an error when adding a dependency
[Java] Create a collection with only one element
When deploying to Heroku, OpenApp causes an error
Try adding text to an image in Scala using the Java standard library
[Java] How to convert one element of a String type array to an Int type
Java: Use Stream to sort the contents of the collection
I want to return a type different from the input element with Java8 StreamAPI reduce ()
[Rails] Processing after adding a column to the devise table
After setting database to mysql, bundle install causes an error
Create a method to return the tax rate in Java
A validation error occurred when saving to the intermediate table.
Display an error screen during the download process to response
A memorandum to reach the itchy place for Java Gold
Get a non-empty collection from an Optional stream in java
What is a Java collection?
Input to the Java console
About the method to convert a character string to an integer / decimal number (cast data) in Java
[Java] How to search for a value in an array (or list) with the contains method
Sorting a list with an int array as an element (Java) (Comparator)
Connecting to a database with Java (Part 1) Maybe the basic method
I tried to translate the error message when executing Eclipse (Java)
Replace with a value according to the match with a Java regular expression
Cast an array of Strings to a List of Integers in Java
[Java] I tried to make a maze by the digging method ♪
How to solve the unknown error when using slf4j in Java
How to check for the contents of a java fixed-length string
How to get the length of an audio file in java
Resolved the error that occurred when trying to use Spark in an environment where Java 8 and Java 11 coexist.
How to set the default fetch size when jOOQ gets an OOM error when fetching a huge result set
Processing to issue an error message
[java8] To understand the Stream API
How to make a Java container
[Java] How to create a folder
Welcome to the Java Library Swamp! !!
The road from JavaScript to Java
How to make a Java array
[Rails] I learned about migration files! (Adding a column to the table)
A collection of phrases that impresses the "different feeling" of Java and JavaScript
The story of forgetting to close a file in Java and failing
A program that determines whether the entered integer is close to an integer
[Java] How to turn a two-dimensional array with an extended for statement
Rails tutorial Resolved an error deploying to Heroku, so note the solution
Get the type of an array element to determine if it is an array
How to find out the Java version of a compiled class file
[Java small story] Monitor when a value is added to the List
[Java] How to get to the front of a specific string using the String class
After adding a Gem, it says There was an error parsing `Gemfile`
I want to display an error message when registering in the database
How to get the absolute path of a directory running in Java
I want to ForEach an array with a Lambda expression in Java
Deploy a Node.js application to an ECS instance using the Cloud Toolkit
How to make an app with a plugin mechanism [C # and Java]
Set up a Java GUI in a separate thread to keep the main
What to do if you get an "A server is already running." Error when you try to start the rails server
[Note] [Beginner] How to write when changing the value of an array element in a Ruby iterative statement
An error occurred when executing a function from MyBatis with the OUT parameter set to CURSOR in PostgreSQL.