CollectorMutability

WARNING

FragileCode

View source code on GitHub

Summary

Avoid Collectors.to{List,Map,Set} in favor of collectors that emphasize (im)mutability

Suppression

Suppress false positives by adding the suppression annotation @SuppressWarnings("CollectorMutability") to the enclosing element.

Disable this pattern completely by adding -Xep:CollectorMutability:OFF as compiler argument. Learn more.

Samples

Replacement

Shows the difference in example code before and after the bug pattern is applied.

+import static com.google.common.collect.ImmutableList.toImmutableList;
+import static com.google.common.collect.ImmutableMap.toImmutableMap;
+import static com.google.common.collect.ImmutableSet.toImmutableSet;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toMap;
 import static java.util.stream.Collectors.toSet;
 
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import reactor.core.publisher.Flux;
 
 class A {
   void m() {
-    Flux.just(1).collect(Collectors.toList());
-    Flux.just(2).collect(toList());
+    Flux.just(1).collect(toImmutableList());
+    Flux.just(2).collect(toImmutableList());
 
-    Stream.of("foo").collect(Collectors.toMap(String::getBytes, String::length));
-    Stream.of("bar").collect(toMap(String::getBytes, String::length));
-    Flux.just("baz").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));
-    Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b));
+    Stream.of("foo").collect(toImmutableMap(String::getBytes, String::length));
+    Stream.of("bar").collect(toImmutableMap(String::getBytes, String::length));
+    Flux.just("baz").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));
+    Flux.just("qux").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> b));
 
-    Stream.of(1).collect(Collectors.toSet());
-    Stream.of(2).collect(toSet());
+    Stream.of(1).collect(toImmutableSet());
+    Stream.of(2).collect(toImmutableSet());
   }
 }
 
+import static java.util.stream.Collectors.toCollection;
 import static java.util.stream.Collectors.toList;
 import static java.util.stream.Collectors.toMap;
 import static java.util.stream.Collectors.toSet;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import reactor.core.publisher.Flux;
 
 class A {
   void m() {
-    Flux.just(1).collect(Collectors.toList());
-    Flux.just(2).collect(toList());
+    Flux.just(1).collect(toCollection(ArrayList::new));
+    Flux.just(2).collect(toCollection(ArrayList::new));
 
-    Stream.of("foo").collect(Collectors.toMap(String::getBytes, String::length));
-    Stream.of("bar").collect(toMap(String::getBytes, String::length));
-    Flux.just("baz").collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b));
-    Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b));
+    Stream.of("foo")
+        .collect(
+            Collectors.toMap(
+                String::getBytes,
+                String::length,
+                (a, b) -> {
+                  throw new IllegalStateException();
+                },
+                HashMap::new));
+    Stream.of("bar")
+        .collect(
+            toMap(
+                String::getBytes,
+                String::length,
+                (a, b) -> {
+                  throw new IllegalStateException();
+                },
+                HashMap::new));
+    Flux.just("baz")
+        .collect(Collectors.toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));
+    Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> b, HashMap::new));
 
-    Stream.of(1).collect(Collectors.toSet());
-    Stream.of(2).collect(toSet());
+    Stream.of(1).collect(toCollection(HashSet::new));
+    Stream.of(2).collect(toCollection(HashSet::new));
   }
 }
 

Identification

Shows code lines which will (not) be flagged by this bug pattern.
A //BUG: Diagnostic contains: comment is placed above any violating line.

import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import reactor.core.publisher.Flux;

class A {
  void m() {
    // BUG: Diagnostic contains:
    Flux.just(1).collect(Collectors.toList());
    // BUG: Diagnostic contains:
    Flux.just(2).collect(toList());
    Flux.just(3).collect(toImmutableList());
    Flux.just(4).collect(toCollection(ArrayList::new));

    // BUG: Diagnostic contains:
    Flux.just("foo").collect(Collectors.toMap(String::getBytes, String::length));
    // BUG: Diagnostic contains:
    Flux.just("bar").collect(toMap(String::getBytes, String::length));
    Flux.just("baz").collect(toImmutableMap(String::getBytes, String::length));
    // BUG: Diagnostic contains:
    Flux.just("qux").collect(toMap(String::getBytes, String::length, (a, b) -> a));
    Flux.just("quux").collect(toImmutableMap(String::getBytes, String::length, (a, b) -> a));
    Flux.just("quuz").collect(toMap(String::getBytes, String::length, (a, b) -> a, HashMap::new));

    // BUG: Diagnostic contains:
    Stream.of(1).collect(Collectors.toSet());
    // BUG: Diagnostic contains:
    Stream.of(2).collect(toSet());
    Stream.of(3).collect(toImmutableSet());
    Stream.of(4).collect(toCollection(HashSet::new));

    Flux.just("foo").collect(Collectors.joining());
  }
}

Copyright © 2017-2024 Picnic Technologies BV