toList() vs collect(Collectors.toList())

I had some extra time this week so went through a bunch of Sonar findings. One was interesting – in Java 17 you can use .toList() instead of .collect(Collectors.toList()) on a stream.

[Yes, I know this was introduced in Java 16. I live in a world where only LTS releases matter]

Cool. I can fix a lot of these without thinking. It’s a search and replace on the project level after all. I then ran the JUnit regression tests and got failures. That was puzzling to me because I’ve been using .toList() in code I write for a good while without incident.

After looking into it, I found the problem. .toList() guarantees the returned List is immutable. However, Collectors.toList() makes no promises about immutability. The result might be immutable. Or you can change it freely. Surprise?

That’s according to the spec. On the JDK I’m using (and Jenkins is using), Collectors.toList() was returning an ArrayList. So people were treating the returned List as mutable and it was working. I added a bunch of “let’s make this explicitly mutable” and then I was able to commit.

Here’s an example that illustrates the diference

import java.util.*;
import java.util.stream.*;

public class PlayTest {

	public static void main(String[] args) {

		var list = List.of("a", "b", "c");
		var collectorReturned = collector(list);
		var toListReturned = toList(list);
		
		System.out.println(collectorReturned.getClass());  // ArrayList (but doesn't have to be)
		System.out.println(toListReturned.getClass());  // class java.util.ImmutableCollections$ListN
		
		collectorReturned.add("x");
		System.out.println(collectorReturned);  // [bb, cc, x]
		toListReturned.add("x");  // throws UnsupportedOperationException

	}

	private static List<String> toList(List<String> list) {
		return list.stream()
				.filter(s -> ! s.equals("a"))
				.map(s -> s + s)
				.toList();
	}

	private static List<String> collector(List<String> list) {
		return list.stream()
				.filter(s -> ! s.equals("a"))
				.map(s -> s + s)
				.collect(Collectors.toList());
				
	}

Collectors.toList() also makes no promises about serializablity or thread safety but I wasn’t expecting it to.

Turning off SonarLint for a project in Eclipse

Overall, I like using SonarLint in Eclipse. When I’m doing something like working on the CodeRanch forums, being informed of possible problems is great. When working on mock exam questions, not so much. Mock exam questions have lots of System.out.println statements. They also have a variety of poor coding practices for anywhere other a certification exam.

Luckily, turning off SonarLint for a project is a simple two part operation.

Part 1 – Turn off Sonar Lint for the project

  1. Just go to the project preferences and choose SonarLint.
  2. Then uncheck “Run SonarLint” automatically.

If you have the foresight to do this before you’ve opened any files in the project, you are done. If not, there is part 2.

Part 2 – Delete any issues thus far

  1. Open the SonarLint Issues view.
  2. Select all. (Ctrl-A is your friend).
  3. Right click and choose Delete.
  4. Choose yes when asked if you are sure.

That’s it. I’m glad I ddi this. Less than a couple of minutes of effort and now I don’t have blue squiggles in all my mock exam stuff!