Java trim():在修剪之前检查空字符串的最简洁方法?

5
我使用trim()方法来修剪某些字符串字段中的前导和尾随空格。
siteRequest.getName().trim();

然而,当字符串字段为空时,会像预期的那样抛出异常。我可以像下面所示在修剪之前检查值:
siteRequest.getName() ? siteRequest.getName() : siteRequest.getName().trim();

但是,如果可能的话,我希望有一种更简洁的方式,因为已经有几个人遇到了这个问题。有什么更聪明的方法可以建议吗?


1
Java不是一种“真值”语言,你是想说siteRequest.getName() == null吗?使用普通的Java,你可以采用三元运算符的方式siteRequest.getName() == null ? null : /* other value */,或者如果已经是Optional形式,可以使用Optional#map。在Java中没有像Kotlin/Scala中那样的Elvis操作符,你不能这样做:siteRequest.getName()?.trim() - Rogue
你有getName()方法的代码访问权限吗?也许你可以在那里处理这个无聊的问题。 - DevilsHnd
@Rogue 感谢您提供有用的信息,是的,我指的是 siteRequest.getName() == null ?。在提问之前,我也尝试使用 siteRequest.getName()?.trim(),但正如您所提到的,Java不支持它。 - user19254373
1
这是一个问题...从getName()返回的名称是否需要有前导或尾随空格?这取决于实际Getter或任何Getter的用途。如果创建了一个类实例对象,您可能会怀疑它可能有一个名称或者至少有一个临时替代方案,例如:return ((this.name == null || this.name.isEmpty()) ? "N/A" : this.name);。同样,这取决于Getter的用途以及您的应用程序如何使用它。 - DevilsHnd
@DevilsHnd 在这个场景中,我认为使用一个Util方法会更好。感谢你的帮助,已点赞 ;) - user19254373
显示剩余2条评论
5个回答

6

我喜欢 @Sebastiaan van den Broek 提出的想法,但宁愿不使用该库,而是查找其实现

// Trim
//-----------------------------------------------------------------------
/**
 * <p>Removes control characters (char &lt;= 32) from both
 * ends of this String, handling {@code null} by returning
 * {@code null}.</p>
 *
 * <p>The String is trimmed using {@link String#trim()}.
 * Trim removes start and end characters &lt;= 32.
 * To strip whitespace use {@link #strip(String)}.</p>
 *
 * <p>To trim your choice of characters, use the
 * {@link #strip(String, String)} methods.</p>
 *
 * <pre>
 * StringUtils.trim(null)          = null
 * StringUtils.trim("")            = ""
 * StringUtils.trim("     ")       = ""
 * StringUtils.trim("abc")         = "abc"
 * StringUtils.trim("    abc    ") = "abc"
 * </pre>
 *
 * @param str  the String to be trimmed, may be null
 * @return the trimmed string, {@code null} if null String input
 */
public static String trim(final String str) {
    return str == null ? null : str.trim();
}

在我看来,没有比这更好实现的方式。使用可选项不是一个选择。因此,该问题中的原始解决方案思路得到确认。


通常我不会在方法参数中使用 final 关键字。但是我认为你的例子与 String 的不可变性有关。如果我们不在 str 参数上使用 final,那么会导致 str.trim() 在字符串池中创建一个新的 String 吗? - user19254373
  1. 对于需要修剪的每个属性的getter,使用这些空控制和修剪怎么样?当我们需要修剪新属性时,这需要太多的工作吗?
- user19254373
在 **1.**:请参见 https://dev59.com/YnRB5IYBdhLWcg3wz6ed 它对 str.trim() 的行为没有影响。 - Franck
在 **2.**:我认为调用静态方法和对每个属性进行修剪(这很可能总是生成一个新字符串)对请求处理的整体性能没有明显影响。 - Franck
String 已经是不可变的,所以如果没有被修剪过,使用 #trim 会导致一个不同于原始对象的 String 对象。问题评论中的部分原因是为了表明你可以在设置 name 参数时进行 #trim,而不是在检索它时进行。 - Rogue

1

不幸的是,Java仍然缺乏一个空安全导航运算符。最接近复制它的方法是使用Optional

String trimmed = Optional.ofNullable(untrimmed).map(String::trim).orElse(null);

然而,很容易看出这种方法并不比简单的三元运算符更好。它的亮点在于如果你有一长串可能为空的值,并且想要避免嵌套的三元运算符:

String trimmed = Optional.ofNullable(request)
 .map(Request::getName)
 .map(String::trim)
 .orElse(null);

打败我 19 秒 :/ - daniu
在需要修剪的每个属性的getter中使用这些null控制和trim怎么样?当我们需要修剪新属性时,这会花费太多的工作吗? - user19254373
@Jonathan:如果你发现自己经常这样做,你可以像其他人发布的那样制作一个空值安全的帮助方法。然而,我会质疑为什么你会在很多属性中这样做。这通常是你不信任数据对象的字段的迹象。如果字段有前导/尾随空格是无效的,那么在构造对象时应该进行验证(或修剪)。然后你的getter只需返回存储的值。如果该空格是合法的,则你的属性不应假定代码调用者想要修剪它。 - Mark Peters
非常感谢,点赞了。这似乎也是合乎逻辑的,但我只是想确定Java中的一般约定(针对这种情况)。在这种情况下,我认为检查getter中的值也是一个好主意,对吧? - user19254373
另外,您能否给siteName属性的getter应用必要逻辑提供一个示例? - user19254373

1
通常使用Apache Commons库的trim方法来完成这个操作。这个库是如此普遍,以至于它基本上是Java的一部分。它对于null字符串会返回null。例如:StringUtils.trim("myString "); 将返回 "myString"

1
不是来自OP的,而是我自己的。仅建议使用库而没有明确显示OP在使用的答案并不太有用,因为并非每个人都可以简单地添加commons、guava或其他类似的库。其次,只提供链接而没有进一步解释的答案被视为无效答案,并往往会在审核队列中被删除。 - Rogue
不是针对你,但在Java世界中,Apache Commons库不仅仅是“一个库”。文档也不会消失。请理性思考。 - Sebastiaan van den Broek
1
StringUtils 的文档链接在过去8年中已经更改了3次(从链接中的 javadocs/apidocs 更改以及 api3.3)。它也绝对不会被包含在每个Java项目中,有许多原因不包括库,特别是内部项目和许可证问题(即使使用Apache许可证)。虽然对你来说可能感觉无处不在,但那只是一个人的经验。我会撤销对未包含示例用法的投票,但请记住这些事情。 - Rogue
@Rogue 更改了,确实。虽然这些很可能是示例改进,因为行为本质上并没有改变。完全删除? 不是的。 StackOverflow的目的不是成为Apache库文档(已过时的)副本。如果他们不想包含某个库,那么他们可以随时将其实现用作灵感来源。 - Sebastiaan van den Broek
@Jonathan 我完成了。 - Sebastiaan van den Broek
@Jonathan,提醒一下,由于您正在使用Spring Boot,如果您真的不想要额外的库,那么很有可能您已经拥有了Spring的StringUtils类,它也可以完成这个任务。 - Sebastiaan van den Broek

0
String name = siteRequest.getName();

name == null ? name : 
name.trim();

或者

String name = siteRequest.getName();

if(name != null)
  name.trim();

是的,但我不想像我在问题中提到的那样使用。我需要一种更简洁的方式。 - user19254373

0

如上所述,只需使用一个实用方法即可完成此操作。理想情况下,null conditional 运算符会使其更好,但在Java中不存在该运算符。

但是可以创建一个实用方法。根据需要进行调整,例如从上面的答案中,您可以执行以下操作:

public static String trim(final String str) {
    return str == null ? null : str.trim();
}

或者如果你想返回一个默认值

public static String trim(final String str) {
    return str == null ? "default_value" : str.trim();
}

或者

public static String trim(final String str, String defaultValue) {
    return str == null ? defaultValue : str.trim();
}

如果您想要使用选项,可以这样做:
public static Option<String> trim(final String str) {
    return str == null ? Optional.nullable() : Optional.of(str.trim());
}

这完全取决于您的需求以及源代码的编写方式。


非常感谢您在方法说明中提供的良好解释和注释。我需要澄清以下几点 >>> - user19254373
通常情况下,我不会在方法参数中使用“final”关键字。但是,我认为在您的示例中使用它与字符串的不可变性有关。如果我们不对“str”参数使用“final”,那么会导致“str.trim()”在字符串池中创建一个新的字符串吗? - user19254373
  1. 对于需要修剪的每个属性的getter,使用这些空控制和修剪怎么样?当我们需要修剪新属性时,这需要太多的工作吗?
- user19254373
@Jonathan 在这里查看 https://dev59.com/QGkv5IYBdhLWcg3w9lai - Dhruv Pal
在1号:@Jonathan,理想情况下,字符串默认是不可变的,因此它不会产生任何影响。只是有人没有创建涉及str =“some value”的逻辑。因此,它将直接给出编译错误。但是,如果我们有非不可变参数,例如普通列表,则其值会突出显示。 - Dhruv Pal
显示剩余3条评论

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