使 String.format("%s", arg) 以不同于 "null" 的方式显示空值参数

Posted

技术标签:

【中文标题】使 String.format("%s", arg) 以不同于 "null" 的方式显示空值参数【英文标题】:Make String.format("%s", arg) display null-valued arguments differently from "null" 【发布时间】:2013-12-05 15:59:55 【问题描述】:

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

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

如果someField 为空,则生成this is null

有没有办法将空值参数的默认null 字符串表示形式覆盖到另一个文本,即? 而不在toString 方法中显式调用replaceAll(...)

注意:该 bean 继承自可以实现 Formattable (http://docs.oracle.com/javase/7/docs/api/java/util/Formattable.html) 的超类,但我似乎不明白如何实现这一点。

编辑:为了举例,sn-p 被过度简化了,但我不是在寻找三元运算符解决方案someField==null ? "?" : someField,因为:

toString() 可能(可能)涉及很多字段,因此检查所有字段过于繁琐且不够流畅。 我无法控制的其他人(如果有的话)正在编写他们自己的子类。 如果一个方法被调用并返回 null,这意味着调用该方法两次或声明一个局部变量。

相反,可以使用Formattable 接口或使用一些自定义Formatter(顺便说一句是final)来完成任何事情吗?

【问题讨论】:

我愿意String.format("this is %s", this.someField==null?"?":this.someField); 或与番石榴:String.format("this is %s", Objects.firstNotNull(this.someField, "?")); 我总是很喜欢firstNotNull,尤其是。类似的实现一些SQL方言,但是Guava的依赖太重,属于Utils类的依赖而不是pojo,imo的依赖。 @VH-NZZ 有一些很棒的解决方案。确定不能选择接受? @KimKern 大多数(如果不是全部)以某种方式解决问题并最终产生与问题兼容的结果,尽管需要付出一些代价。话虽如此,我客观上不能断言我可以选择 one 答案作为真正优秀的,因此:不,在这个阶段我恐怕不能。 【参考方案1】:

使用 java 8,您现在可以为此使用 Optional 类:

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

【讨论】:

要同时申请 'empty' 值,可以使用 'filter(s -> !s.isEmpty())' 扩展如下: System.out.printf("myString: % s", ofNullable(myString).filter(s -> !s.isEmpty()).orElse("未找到")【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

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

Guava docs.

【讨论】:

String.format("this is %s", StringUtils.defaultIfBlank(this.someField, "")); 如果 Apache StringUtils 恰好在您的类路径上,则可以解决问题。【参考方案4】:

这个主题有点晚了,但这可能是一个看起来很干净的解决方案: 首先,创建自己的格式方法...

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);

这消除了对多个难以阅读的三元运算符的需要。

【讨论】:

... 但暗示依赖于您的 formatNull 方法。 当然!除非前面提到的案例特定于某些输出策略类,否则该方法可以在策略本身中私有定义。那么就不会有依赖问题了。如果它在应用程序中的许多地方使用,那么是的,它需要放在某个库/实用程序类中。【参考方案5】:

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

但如果有时间这可能会再次分配null。所以你可以对这种情况使用验证

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

【讨论】:

【参考方案6】:

为避免重复三元运算符,您可以将其包装在更易读的方法中,该方法将检查您的对象是否为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  

【讨论】:

【参考方案7】:

你可以这样做

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

【讨论】:

再次,这是使用三元运算符。还是谢谢。【参考方案8】:

从 java 7 开始,您可以使用Objects.toString(Object o, String nullDefault)

应用于您的示例:String.format("this is %s", Objects.toString(this.someField, "?"));

【讨论】:

【参考方案9】:
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);

然后使用方法,ok

【讨论】:

【参考方案10】:

要保留someField 的原始值(如果null 是有效值),您可以使用ternary operator。

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

【讨论】:

以上是关于使 String.format("%s", arg) 以不同于 "null" 的方式显示空值参数的主要内容,如果未能解决你的问题,请参考以下文章

C#中 s +=string.Format("0,1*1,1=2,-4",j,i,j*i)是啥意思?

string.format()的用法?

C#中的String.Format方法输入日志标题

求java高手解答

如何在 C# 中将“”添加到 string.Format [重复]

格式化输出