WARNING
Performance
Simplification
View source code on GitHub
Summary String formatting can be deferred
Summary
String formatting can be deferred
Suppression Suppress false positives by adding the suppression annotation @SuppressWarnings("EagerStringFormatting") to the enclosing element. Disable this pattern completely by adding -Xep:EagerStringFormatting:OFF as compiler argument. Learn more.
Suppression
Suppress false positives by adding the suppression annotation @SuppressWarnings("EagerStringFormatting") to the enclosing element.
@SuppressWarnings("EagerStringFormatting")
Disable this pattern completely by adding -Xep:EagerStringFormatting:OFF as compiler argument. Learn more.
-Xep:EagerStringFormatting:OFF
Shows the difference in example code before and after the bug pattern is applied.
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Verify.verify; import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.Marker; class A { private static final Logger LOG = LoggerFactory.getLogger(A.class); private static final String GUAVA_COMPATIBLE_PATTERN = "with-only-%s-placeholder"; private static final String GUAVA_INCOMPATIBLE_PATTERN = "with-%%-marker"; void m() { - requireNonNull("never-null", String.format("Format string: %s", 0)); + requireNonNull("never-null", () -> String.format("Format string: %s", 0)); - checkArgument(true, String.format("Vacuous format string %%")); - checkNotNull("never-null", "Format string: %s %s%%".formatted(1, 2)); - checkState(false, String.format(Locale.US, "Format string with locale: %s", 3)); - verify(true, GUAVA_COMPATIBLE_PATTERN.formatted(4)); - verifyNotNull("never-null", String.format(Locale.ENGLISH, GUAVA_COMPATIBLE_PATTERN, 5)); - checkArgument(false, GUAVA_INCOMPATIBLE_PATTERN.formatted()); - checkNotNull("never-null", String.format(GUAVA_INCOMPATIBLE_PATTERN)); + checkArgument(true, "Vacuous format string %"); + checkNotNull("never-null", "Format string: %s %s%", 1, 2); + checkState(false, "Format string with locale: %s", 3); + verify(true, GUAVA_COMPATIBLE_PATTERN, 4); + verifyNotNull("never-null", GUAVA_COMPATIBLE_PATTERN, 5); + checkArgument(false, "with-%-marker"); + checkNotNull("never-null", "with-%-marker"); - LOG.trace("Vacuous format string %%".formatted()); - LOG.debug(String.format("With format string: %s, %s%%", 6, 7)); - LOG.info(String.format(Locale.ROOT, "With vacuous localized format string %%")); - LOG.warn((Marker) null, "With marker and format string: %s".formatted(8)); - LOG.error( - String.format(Locale.US, "With throwable and format string: %s, %s", 9, 10), - new RuntimeException()); + LOG.trace("Vacuous format string %"); + LOG.debug("With format string: {}, {}%", 6, 7); + LOG.info("With vacuous localized format string %"); + LOG.warn((Marker) null, "With marker and format string: {}", 8); + LOG.error("With throwable and format string: {}, {}", 9, 10, new RuntimeException()); LOG.trace( - (Marker) null, - "With marker, throwable and format string: %s".formatted(11), - new RuntimeException()); - LOG.debug(GUAVA_COMPATIBLE_PATTERN.formatted(12)); - LOG.info(String.format(Locale.ENGLISH, GUAVA_COMPATIBLE_PATTERN, 13)); - LOG.warn(GUAVA_INCOMPATIBLE_PATTERN.formatted()); - LOG.error(String.format(GUAVA_INCOMPATIBLE_PATTERN)); + (Marker) null, "With marker, throwable and format string: {}", 11, new RuntimeException()); + LOG.debug("with-only-{}-placeholder", 12); + LOG.info("with-only-{}-placeholder", 13); + LOG.warn("with-%-marker"); + LOG.error("with-%-marker"); } }
Shows code lines which will (not) be flagged by this bug pattern. A //BUG: Diagnostic contains: comment is placed above any violating line.
//BUG: Diagnostic contains:
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Verify.verify; import static com.google.common.base.Verify.verifyNotNull; import static java.util.Objects.requireNonNull; import java.util.Formattable; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.Marker; class A { private static final Logger LOG = LoggerFactory.getLogger(A.class); private int nonFinalField = 0; void m() { Formattable formattable = (formatter, flags, width, precision) -> {}; int effectivelyFinalLocal = 0; /* A local variable that is also not effectively final. */ int nonFinalLocal = 0; nonFinalLocal = 1; String.format("%s", "foo"); String.format(Locale.US, "%s", "foo"); "%s".formatted("foo"); String.format("%s", "foo", "bar"); String.format("%s %s", "foo", "bar"); String.format("%s %s %%", "foo", "bar"); System.out.println(String.format("%s", nonFinalLocal)); requireNonNull("never-null"); requireNonNull("never-null", () -> String.format("Format string: %s", nonFinalField)); // BUG: Diagnostic matches: VACUOUS requireNonNull(String.format("Never-null format string: %s", nonFinalField)); // BUG: Diagnostic matches: VACUOUS requireNonNull("Never-null format string: %s".formatted(nonFinalField), "message"); // BUG: Diagnostic matches: VACUOUS requireNonNull( String.format("Never-null format string"), String.format("Malformed format string: %")); // BUG: Diagnostic matches: DEFER_EXTRA_VARIABLE requireNonNull("never-null", String.format("Format string: %s", nonFinalLocal)); // BUG: Diagnostic matches: DEFER requireNonNull("never-null", String.format("Format string: %s", effectivelyFinalLocal)); // BUG: Diagnostic matches: DEFER requireNonNull( "never-null", String.format( "Custom format string: %s, %d, %s", getClass(), nonFinalField, "string-constant")); checkArgument(true); checkNotNull("never-null"); checkState(false); verify(true); verifyNotNull("never-null"); checkArgument(false, "Without format string"); checkNotNull("never-null", "Without format string"); checkState(true, "Without format string"); verify(false, "Without format string"); verifyNotNull("never-null", "Without format string"); checkArgument(true, "With format string: %s", nonFinalLocal); checkNotNull("never-null", "With format string: %s", nonFinalLocal); checkState(false, "With format string: %s", nonFinalLocal); verify(true, "With format string: %s", nonFinalLocal); verifyNotNull("never-null", "With format string: %s", nonFinalLocal); // BUG: Diagnostic matches: VACUOUS checkNotNull(String.format("Never-null format string: %s", nonFinalLocal)); // BUG: Diagnostic matches: VACUOUS verifyNotNull("Never-null format string: %s".formatted(nonFinalLocal), "message"); // BUG: Diagnostic matches: VACUOUS checkNotNull( String.format("Never-null format string"), String.format("Malformed format string: %")); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA checkArgument(true, String.format(toString())); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA checkNotNull("never-null", toString().formatted()); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA checkState(true, String.format("Custom format string: %d", nonFinalLocal)); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA verify(true, "Mismatched format string:".formatted(nonFinalLocal)); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA verifyNotNull("never-null", "Mismatched format string: %d".formatted()); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA checkArgument(true, String.format("Malformed format string: %")); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA checkNotNull("never-null", "Format string with `Formattable`: %s".formatted(formattable)); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA checkState(true, String.format("Generated format string: %%s"), nonFinalLocal); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_GUAVA verify( true, "Format string with format string argument: %s", String.format("Format string argument: %s", nonFinalLocal)); // BUG: Diagnostic matches: DEFER verifyNotNull( "never-null", String.format("Format string: %s, %s", nonFinalLocal, nonFinalLocal)); // BUG: Diagnostic matches: DEFER checkArgument(true, "Format string: %s%%".formatted(nonFinalLocal)); // BUG: Diagnostic matches: DEFER checkNotNull( "never-null", String.format(Locale.US, "Format string with locale: %s", nonFinalLocal)); LOG.trace("Without format string"); LOG.debug("With format string: {}", nonFinalLocal); LOG.info((Marker) null, "With marker"); LOG.warn((Marker) null, "With marker and format string: {}", nonFinalLocal); LOG.error("With throwable", new RuntimeException()); LOG.trace("With throwable and format string: {}", nonFinalLocal, new RuntimeException()); LOG.debug((Marker) null, "With marker and throwable", new RuntimeException()); LOG.info( (Marker) null, "With marker, throwable and format string: {}", nonFinalLocal, new RuntimeException()); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.warn(String.format(toString())); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.error(toString().formatted()); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.trace(String.format("Custom format string: %d", nonFinalLocal)); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.debug("Mismatched format string:".formatted(nonFinalLocal)); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.info("Mismatched format string %d:".formatted()); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.warn(String.format("Malformed format string: %")); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.error("Format string with `Formattable`: %s".formatted(formattable)); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.trace(String.format("Generated format string: {}"), nonFinalLocal); // BUG: Diagnostic matches: DEFER_SIMPLIFIED_SLF4J LOG.debug( "Format string with format string argument: {}", String.format("Format string argument: %s", nonFinalLocal)); // BUG: Diagnostic matches: DEFER LOG.info(String.format("Vacuous format string %%")); // BUG: Diagnostic matches: DEFER LOG.warn(String.format("With format string: %s, %s", nonFinalLocal, nonFinalLocal)); // BUG: Diagnostic matches: DEFER LOG.error(String.format(Locale.ROOT, "With vacuous localized format string %%")); // BUG: Diagnostic matches: DEFER LOG.trace((Marker) null, String.format("With marker and format string: %s", nonFinalLocal)); // BUG: Diagnostic matches: DEFER LOG.debug( String.format("With throwable and format string: %s", nonFinalLocal), new RuntimeException()); // BUG: Diagnostic matches: DEFER LOG.info( (Marker) null, String.format("With marker, throwable and format string: %s", nonFinalLocal), new RuntimeException()); } }