EagerStringFormatting
WARNING
Performance
Simplification
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.
Samples
Replacement
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");
}
}
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.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());
}
}