63

我正在尝试检查 Java String 是否不是null,不是空的,也不是空格。

在我看来,这段代码应该很适合这项工作。

public static boolean isEmpty(String s) {
    if ((s != null) && (s.trim().length() > 0))
        return false;
    else
        return true;
}

根据文档,String.trim()应该这样工作:

返回字符串的副本,省略前导和尾随空格。

如果此String对象表示一个空字符序列,或者此对象表示的字符序列的首尾字符String都具有大于'\u0020'(空格字符)的代码,则返回对该String对象的引用。

但是,apache/commons/lang/StringUtils.java它的做法有点不同。

public static boolean isBlank(String str) {
    int strLen;
    if (str == null || (strLen = str.length()) == 0) {
        return true;
    }
    for (int i = 0; i < strLen; i++) {
        if ((Character.isWhitespace(str.charAt(i)) == false)) {
            return false;
        }
    }
    return true;
}

根据文档,Character.isWhitespace()

根据 Java 确定指定字符是否为空格。一个字符是一个 Java 空白字符当且仅当它满足以下条件之一:

  • 它是 Unicode 空格字符(SPACE_SEPARATOR、、LINE_SEPARATORPARAGRAPH_SEPARATOR),但也不是不间断空格('\u00A0'、、、'\u2007''\u202F'
  • 它是'\t',U+0009 水平制表。
  • 它是'\n',U+000A LINE FEED。
  • 它是'\u000B',U+000B 垂直制表。
  • 它是'\f',U+000C 换页。
  • '\r',U+000D 回车。
  • 它是'\u001C',U+001C 文件分隔符。
  • 它是'\u001D',U+001D 组分隔符。
  • 它是'\u001E',U+001E 记录分隔符。
  • 它是'\u001F',U+001F 单位分隔符。

如果我没记错 - 或者我可能只是没有正确阅读它 -String.trim() 应该带走任何正在检查的字符Character.isWhiteSpace()。他们都看到在上面'\u0020'

在这种情况下,更简单的isEmpty功能似乎涵盖了更长的功能涵盖的所有场景isBlank

  1. 是否有一个字符串会使测试用例中的isEmpty和行为不同?isBlank
  2. 假设没有,是否还有其他考虑因素我应该选择isBlank而不使用isEmpty

对于那些对实际运行测试感兴趣的人,这里是方法和单元测试。

public class StringUtil {

    public static boolean isEmpty(String s) {
        if ((s != null) && (s.trim().length() > 0))
            return false;
        else
            return true;
    }

    public static boolean isBlank(String str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }
}

和单元测试

@Test
public void test() {
    
    String s = null; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)) ;
    
    s = ""; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)); 
    
    s = " "; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)) ;
    
    s = "   "; 
    assertTrue(StringUtil.isEmpty(s)) ;
    assertTrue(StringUtil.isBlank(s)) ;
    
    s = "   a     "; 
    assertTrue(StringUtil.isEmpty(s)==false) ;    
    assertTrue(StringUtil.isBlank(s)==false) ;       
    
}

更新:这是一个非常有趣的讨论——这就是我喜欢 Stack Overflow 和这里的人们的原因。顺便说一句,回到问题,我们得到:

  • 一个程序,显示哪些所有字符会使行为不同。代码位于https://ideone.com/ELY5Wv。谢谢@杜克林。
  • 选择标准的性能相关原因isBlank()。谢谢@devconsole。
  • @nhahtdh 的全面解释。谢了哥们。
4

8 回答 8

32

是否有一个字符串会使测试用例中的isEmpty和行为不同?isBlank

请注意,它Character.isWhitespace可以识别 Unicode 字符并返回trueUnicode 空白字符。

根据 Java 确定指定字符是否为空格。一个字符是一个 Java 空白字符当且仅当它满足以下条件之一:

  • 它是 Unicode 空格字符(SPACE_SEPARATOR、、LINE_SEPARATORPARAGRAPH_SEPARATOR),但也不是不间断空格('\u00A0'、、、'\u2007''\u202F'

  • [...]

另一方面,该trim()方法将修剪所有代码点低于 U+0020 的控制字符和空格字符 (U+0020)。

因此,在存在 Unicode 空白字符时,这两种方法的行为会有所不同。例如:"\u2008"或者当字符串包含不按Character.isWhitespace方法考虑空格的控制字符时。例如:"\002"

如果您要编写一个正则表达式来执行此操作(这比通过字符串循环并检查要慢):

  • isEmpty()相当于.matches("[\\x00-\\x20]*")
  • isBlank()相当于.matches("\\p{javaWhitespace}*")

isEmpty()andisBlank()方法都允许nullString 引用,因此它不完全等同于正则表达式解决方案,但抛开这一点,它是等价的)。

请注意\p{javaWhitespace},正如其名称所暗示的那样,它是用于访问由Character.isWhitespace方法定义的字符类的特定于 Java 的语法。

假设没有,是否还有其他考虑因素我应该选择isBlank而不使用isEmpty

这取决于。但是,我认为上面部分的解释应该足以让您决定。总结一下区别:

  • isEmpty()如果字符串仅包含 U+0020 以下的控制字符1和空格字符 (U+0020),则认为该字符串为空

  • isBlank如果字符串仅包含由方法定义的空白字符,则将认为该字符串为空Character.isWhitespace,其中包括 Unicode 空白字符。

1处还有控制字符U+007F DELETE,不通过trim()方法修剪。

于 2013-05-06T08:48:25.937 回答
25

这两种标准方法的目的是区分这两种情况:

org.apache.common.lang.StringUtils.isBlank(" ")(将返回true)。

org.apache.common.lang.StringUtils.isEmpty(" ")(将返回false)。

您的自定义实现isEmpty()将返回true


更新:

  • org.apache.common.lang.StringUtils.isEmpty()用于查找字符串的长度是 0 还是 null。

  • org.apache.common.lang.StringUtils.isBlank()向前迈进了一步。它不仅检查 String 的长度是 0 还是 null,还检查它是否只是一个空白字符串。

在您的情况下,您正在修剪方法中的字符串 isEmpty。现在可能发生的唯一区别不会发生(您给它的情况" "),因为您正在修剪它(删除尾随空格 - 在这种情况下就像删除所有空格)。

于 2013-05-06T08:27:21.040 回答
14

我会选择isBlank()isEmpty()因为trim()创建了一个新的 String 对象,以后必须进行垃圾收集。isBlank()另一方面不创建任何对象。

于 2013-05-06T08:33:40.170 回答
4

您可以查看 JSR 303 Bean Validtion ,其中包含 Annotatinos@NotEmpty@NotNull. Bean Validation 很酷,因为您可以将验证问题与方法的原始意图分开。

于 2013-05-06T08:38:24.387 回答
1

为什么不能简单地使用嵌套三元运算符来实现这一点。请查看示例代码 public static void main(String[] args) { String s = null; String s1=""; String s2="hello"; System.out.println(" 1 "+check(s)); System.out.println(" 2 "+check(s1)); System.out.println(" 3 "+check(s2)); } public static boolean check(String data) { return (data==null?false:(data.isEmpty()?false:true)); }

输出如下

1 假 2 假 3 真

这里第 2 个场景返回 false(即 null 和空),第 3 个场景返回 true

于 2015-07-08T12:25:17.430 回答
0
<% 
System.out.println(request.getParameter("userName")+"*");

if (request.getParameter("userName").trim().length() == 0 | request.getParameter("userName") == null) { %>
<jsp:forward page="HandleIt.jsp" />
<% }
 else { %>
Hello ${param.userName}
<%} %>
于 2014-08-07T10:22:22.813 回答
0

这个简单的代码就足够了:

public static boolean isNullOrEmpty(String str) {
    return str == null || str.trim().equals("");
}

和单元测试:

@Test
public void testIsNullOrEmpty() {
    assertEquals(true, AcdsUtils.isNullOrEmpty(""));
    assertEquals(true, AcdsUtils.isNullOrEmpty((String) null));
    assertEquals(false, AcdsUtils.isNullOrEmpty("lol    "));
    assertEquals(false, AcdsUtils.isNullOrEmpty("HallO"));
}
于 2015-08-06T06:03:05.510 回答
0

在 Java 8 中,您还可以将 Optional 功能与过滤一起使用。要检查字符串是否为空,代码是纯 Java SE,没有额外的库。以下代码说明了 isBlank() 实现。

String.trim() 行为

!Optional.ofNullable(tocheck).filter(e -> e != null && e.trim().length() > 0).isPresent()

StringUtils.isBlank() 行为

Optional.ofNullable(toCheck)
    .filter(e -> 
        {
            int strLen;
            if (str == null || (strLen = str.length()) == 0) {
                return true;
            }
            for (int i = 0; i < strLen; i++) {
                if ((Character.isWhitespace(str.charAt(i)) == false)) {
                    return false;
                }
            }
            return true;

        })
    .isPresent()
于 2016-08-31T20:56:36.960 回答