使String.format("%s", arg)在显示null值参数时与"null"有所区别

51

考虑一个bean的自定义 toString() 实现:

@Override
public String toString() {
    String.format("this is %s", this.someField);
}

如果someField为null,这将产生this is null

有没有一种方法可以覆盖默认的null字符串表示为另一个文本,即?,而不需要在toString方法中显式调用replaceAll(...)

注意:该bean继承自一个可能实现Formattable的超类 (http://docs.oracle.com/javase/7/docs/api/java/util/Formattable.html),但我似乎不知道如何使其工作。

编辑:出于示例简化的考虑,代码片段过于简单,但我不寻找三元运算符解决方案someField==null ? "?" : someField,因为:

  • toString()中可能涉及许多字段,因此检查所有字段太麻烦且不流畅。
  • 其他人(如果有)正在编写自己的子类。
  • 如果调用方法并返回null,则需要两次调用方法或声明一个局部变量。

更准确地说,是否可以使用Formattable接口或具有某些自定义Formatterfinal)来完成任何操作?


2
我会使用 String.format("this is %s", this.someField==null?"?":this.someField); - Arnaud Denoyelle
1
或者使用Guava:String.format("这是%s", Objects.firstNotNull(this.someField, "?")); - Arnaud Denoyelle
我总是对 firstNotNull 念念不忘,特别是一些 SQL 方言中的类似实现,但 Guava 太重了,更适合作为 Utils 类的依赖而非 POJO 的依赖。 - VH-NZZ
@VH-NZZ 有一些很好的解决方案。你确定不能选择一个来接受吗? - Kim Kern
@KimKern 大多数,如果不是全部,都以某种方式解决了问题,并最终产生了与问题兼容的结果,尽管代价有些高。话虽如此,我客观地不能断言我可以选择一个答案作为真正优越的答案,因此:不,目前我恐怕不能这样做。 - VH-NZZ
10个回答

63

使用 Java 8,你现在可以使用 Optional 类来实现这一点:

import static java.util.Optional.ofNullable;
...
String myString = null;
System.out.printf("myString: %s",
    ofNullable(myString).orElse("Not found")
);

为了对空值进行申请,可以使用以下语句进行扩展:'filter(s -> !s.isEmpty())' System.out.printf("myString: %s", ofNullable(myString).filter(s -> !s.isEmpty()).orElse("Not found")) - burak

47

对于一个不需要外部库的Java 7解决方案:

String.format("this is %s", Objects.toString(this.someField, "?"));

使用Java 17,您可以这样使用: "this is %s".formatted("this is %s", Objects.toString(this.someField, "?")) - Leonardo Campos

22

在我看来,最好的解决方案是使用Guava的Objects方法,即firstNonNull。以下这个方法将确保如果someField为空,则打印一个空字符串。

String.format("this is %s", MoreObjects.firstNonNull(this.someField, ""));

Guava文档


10
如果 Apache StringUtils 在你的类路径中,String.format("this is %s", StringUtils.defaultIfBlank(this.someField, "")); 将会解决问题。该语句会使用 Apache StringUtils 库来格式化字符串,并在 this.someField 为空时提供一个默认值。 - dvtoever

6

虽然有点晚了,但这可能是一个非常简洁的解决方案: 首先,创建自己的格式方法...

private static String NULL_STRING = "?";

private static String formatNull(String str, Object... args){
    for(int i = 0; i < args.length; i++){
        if(args[i] == null){
            args[i] = NULL_STRING;
        }
    }

    return String.format(str, args);
}

然后,按照自己的意愿使用它...

@Test
public void TestNullFormat(){
    Object ob1 = null;
    Object ob2 = "a test";

    String str = formatNull("this is %s", ob1);
    assertEquals("this is ?", str);

    str = formatNull("this is %s", ob2);
    assertEquals("this is a test", str);
}

这样可以消除多个难以阅读的三元运算符的需求。

1
...但意味着依赖于你的formatNull方法。 - VH-NZZ
当然!除非上述情况是特定于某个输出策略类,其中可以在策略本身中私有定义该方法。那么就不会有依赖问题。如果它在应用程序中的许多地方都被使用,则需要将其放入某个库/工具类中。 - JM Lord

5

如果您不想使用replaceAll(),您可以为someField赋一个默认的文本(字符串)。

但是,如果有时可能会再次分配null。 因此,您可以为该情况使用验证。

 this.someField == null ? "defaultText" : this.someField

4
为了避免重复使用三元运算符,您可以将其包装在更易读的方法中,并检查您的对象是否为null,如果是,则返回一些默认值,例如:
static <T> T changeNull(T arg, T defaultValue) {
    return arg == null ? defaultValue : arg;
}

使用方法

String field = null;
Integer id = null;
System.out.printf("field is %s %n", changeNull(field, ""));
System.out.printf("id is %d %n", changeNull(id, -1));
System.out.printf("id is %s %n", changeNull(field, ""));

输出:

field is  
id is -1 
id is  

3
你可以直接执行

String.format("this is %s", (this.someField==null?"DEFAULT":this.someField));

再次强调,这是使用三元运算符。无论如何感谢您。 - VH-NZZ

3
从Java 7开始,你可以使用Objects.toString(Object o, String nullDefault)方法。
在你的例子中应用: String.format("这是%s", Objects.toString(this.someField, "?"));

2
public static String format(String format, Object... args){
    for (int i=0;i<args.length;i++){
        if (args[i]==null) args[i]="";
    }
    return String.format(format,args);
}

然后使用这个方法,好的。

1
为了保留someField的原始值(以防null是有效值),您可以使用三元运算符
String.format("This is %s", (this.someField == null ? "unknown" : this.someField));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接