Skip to main content Link Search Menu Expand Document (external link)

MethodReferenceUsage

SUGGESTION

Style

View source code on GitHub

Summary

Prefer method references over lambda expressions

Suppression

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

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

Samples

Replacement

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

 import static java.util.Collections.emptyList;
 
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 class A {
   static class B extends A {
     final A a = new B();
     final B b = new B();
 
     IntSupplier intSup;
     Supplier<List<?>> listSup;
 
     void m() {
-      intSup = () -> a.iint0();
-      intSup = () -> b.iint0();
-      intSup = () -> this.iint0();
-      intSup = () -> super.iint0();
+      intSup = a::iint0;
+      intSup = b::iint0;
+      intSup = this::iint0;
+      intSup = super::iint0;
 
       intSup = () -> a.sint0();
       intSup = () -> b.sint0();
       intSup = () -> this.sint0();
       intSup = () -> super.sint0();
-      intSup = () -> A.sint0();
-      intSup = () -> B.sint0();
+      intSup = A::sint0;
+      intSup = B::sint0;
 
-      listSup = () -> Collections.emptyList();
-      listSup = () -> emptyList();
+      listSup = Collections::emptyList;
+      listSup = Collections::emptyList;
 
-      Stream.of((Class<?>) int.class).filter(c -> c.isEnum());
-      Stream.of((Map<?, ?>) null).map(Map::keySet).map(s -> s.size());
+      Stream.of((Class<?>) int.class).filter(Class::isEnum);
+      Stream.of((Map<?, ?>) null).map(Map::keySet).map(Set::size);
     }
 
     @Override
     int iint0() {
       return 0;
     }
   }
 
   int iint0() {
     return 0;
   }
 
   static int sint0() {
     return 0;
   }
 }

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 com.google.common.collect.Streams;
import java.util.HashMap;
import java.util.Map;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.stream.Stream;

class A {
  private final Stream<Integer> s = Stream.of(1);
  private final Map<Integer, Integer> m = new HashMap<>();
  private final Runnable thrower =
      () -> {
        throw new RuntimeException();
      };

  void unaryExternalStaticFunctionCalls() {
    s.forEach(String::valueOf);
    // BUG: Diagnostic contains:
    s.forEach(v -> String.valueOf(v));
    s.forEach(
        // BUG: Diagnostic contains:
        (v) -> {
          String.valueOf(v);
        });
    s.forEach(
        // BUG: Diagnostic contains:
        (Integer v) -> {
          {
            String.valueOf(v);
          }
        });
    s.forEach(
        v -> {
          String.valueOf(v);
          String.valueOf(v);
        });

    s.map(String::valueOf);
    // BUG: Diagnostic contains:
    s.map(v -> String.valueOf(v));
    // BUG: Diagnostic contains:
    s.map((v) -> (String.valueOf(v)));
    s.map(
        // BUG: Diagnostic contains:
        (Integer v) -> {
          return String.valueOf(v);
        });
    s.map(
        // BUG: Diagnostic contains:
        (final Integer v) -> {
          return (String.valueOf(v));
        });
    s.map(
        v -> {
          String.valueOf(v);
          return String.valueOf(v);
        });

    s.findFirst().orElseGet(() -> Integer.valueOf("0"));
    m.forEach((k, v) -> String.valueOf(v));
    m.forEach((k, v) -> String.valueOf(k));
  }

  void binaryExternalInstanceFunctionCalls() {
    m.forEach(m::put);
    // BUG: Diagnostic contains:
    m.forEach((k, v) -> m.put(k, v));
    m.forEach((k, v) -> m.put(v, k));
    m.forEach(
        // BUG: Diagnostic contains:
        (Integer k, Integer v) -> {
          m.put(k, v);
        });
    m.forEach(
        (k, v) -> {
          m.put(k, k);
        });
    m.forEach(
        // BUG: Diagnostic contains:
        (final Integer k, final Integer v) -> {
          {
            m.put(k, v);
          }
        });
    m.forEach(
        (k, v) -> {
          {
            m.put(v, v);
          }
        });
    m.forEach((k, v) -> new HashMap<Integer, Integer>().put(k, v));
    m.forEach(
        (k, v) -> {
          m.put(k, v);
          m.put(k, v);
        });

    Streams.zip(s, s, m::put);
    // BUG: Diagnostic contains:
    Streams.zip(s, s, (a, b) -> m.put(a, b));
    Streams.zip(s, s, (a, b) -> m.put(b, a));
    // BUG: Diagnostic contains:
    Streams.zip(s, s, (Integer a, Integer b) -> (m.put(a, b)));
    Streams.zip(s, s, (a, b) -> (m.put(a, a)));
    Streams.zip(
        s,
        s,
        // BUG: Diagnostic contains:
        (final Integer a, final Integer b) -> {
          return m.put(a, b);
        });
    Streams.zip(
        s,
        s,
        (a, b) -> {
          return m.put(b, b);
        });
    Streams.zip(
        s,
        s,
        // BUG: Diagnostic contains:
        (a, b) -> {
          return (m.put(a, b));
        });
    Streams.zip(
        s,
        s,
        (a, b) -> {
          return (m.put(b, a));
        });
    Streams.zip(
        s,
        s,
        (a, b) -> {
          m.put(a, b);
          return m.put(a, b);
        });
  }

  void nullaryExternalInstanceFunctionCalls() {
    s.map(Integer::doubleValue);
    // BUG: Diagnostic contains:
    s.map(i -> i.doubleValue());
    s.map(i -> i.toString());
    s.map(i -> s.toString());

    // BUG: Diagnostic contains:
    Stream.of(int.class).filter(c -> c.isEnum());
    Stream.of((Class<?>) int.class).filter(Class::isEnum);
    // BUG: Diagnostic contains:
    Stream.of((Class<?>) int.class).filter(c -> c.isEnum());
  }

  void localFunctionCalls() {
    s.forEach(v -> ivoid0());
    s.forEach(v -> iint0());
    s.forEach(v -> svoid0());
    s.forEach(v -> sint0());

    s.forEach(this::ivoid1);
    // BUG: Diagnostic contains:
    s.forEach(v -> ivoid1(v));
    s.forEach(
        // BUG: Diagnostic contains:
        v -> {
          ivoid1(v);
        });
    s.forEach(this::iint1);
    // BUG: Diagnostic contains:
    s.forEach(v -> iint1(v));
    s.forEach(
        // BUG: Diagnostic contains:
        v -> {
          iint1(v);
        });

    s.forEach(A::svoid1);
    // BUG: Diagnostic contains:
    s.forEach(v -> svoid1(v));
    s.forEach(
        // BUG: Diagnostic contains:
        v -> {
          svoid1(v);
        });
    s.forEach(A::sint1);
    // BUG: Diagnostic contains:
    s.forEach(v -> sint1(v));
    s.forEach(
        // BUG: Diagnostic contains:
        v -> {
          sint1(v);
        });

    s.forEach(v -> ivoid2(v, v));
    s.forEach(v -> iint2(v, v));
    s.forEach(v -> svoid2(v, v));
    s.forEach(v -> sint2(v, v));

    m.forEach((k, v) -> ivoid0());
    m.forEach((k, v) -> iint0());
    m.forEach((k, v) -> svoid0());
    m.forEach((k, v) -> sint0());

    m.forEach(this::ivoid2);
    // BUG: Diagnostic contains:
    m.forEach((k, v) -> ivoid2(k, v));
    m.forEach(
        // BUG: Diagnostic contains:
        (k, v) -> {
          ivoid2(k, v);
        });
    m.forEach(this::iint2);
    // BUG: Diagnostic contains:
    m.forEach((k, v) -> iint2(k, v));
    m.forEach(
        // BUG: Diagnostic contains:
        (k, v) -> {
          iint2(k, v);
        });

    m.forEach(A::svoid2);
    // BUG: Diagnostic contains:
    m.forEach((k, v) -> svoid2(k, v));
    m.forEach(
        // BUG: Diagnostic contains:
        (k, v) -> {
          svoid2(k, v);
        });
    m.forEach(A::sint2);
    // BUG: Diagnostic contains:
    m.forEach((k, v) -> sint2(k, v));
    m.forEach(
        // BUG: Diagnostic contains:
        (k, v) -> {
          sint2(k, v);
        });
  }

  void functionCallsWhoseReplacementWouldBeAmbiguous() {
    receiver(
        i -> {
          Integer.toString(i);
        });
  }

  void assortedOtherEdgeCases() {
    s.forEach(v -> String.valueOf(v.toString()));
    TernaryOp o1 = (a, b, c) -> String.valueOf(a);
    TernaryOp o2 = (a, b, c) -> String.valueOf(b);
    TernaryOp o3 = (a, b, c) -> String.valueOf(c);
    TernaryOp o4 = (a, b, c) -> c.concat(a);
    TernaryOp o5 = (a, b, c) -> c.concat(b);
    TernaryOp o6 = (a, b, c) -> a.concat(c);
    TernaryOp o7 = (a, b, c) -> b.concat(c);
  }

  void receiver(IntFunction<?> op) {}

  void receiver(IntConsumer op) {}

  void ivoid0() {}

  void ivoid1(int a) {}

  void ivoid2(int a, int b) {}

  int iint0() {
    return 0;
  }

  int iint1(int a) {
    return 0;
  }

  int iint2(int a, int b) {
    return 0;
  }

  static void svoid0() {}

  static void svoid1(int a) {}

  static void svoid2(int a, int b) {}

  static void svoid3(int a, int b, int c) {}

  static int sint0() {
    return 0;
  }

  static int sint1(int a) {
    return 0;
  }

  static int sint2(int a, int b) {
    return 0;
  }

  interface TernaryOp {
    String collect(String a, String b, String c);
  }
}

Copyright © 2017-2023 Picnic Technologies BV