在Java中检查非空,而不是空白的字符串

时间:2013-05-06 08:24:59

标签: java string

我正在尝试检查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_SEPARATORLINE_SEPARATORPARAGRAPH_SEPARATOR),但也不是一个不间断的空格('\u00A0''\u2007''\u202F')。
  •   
  • '\t',U + 0009 HORIZONTAL TABULATION。
  •   
  • '\n',U + 000A LINE FEED。
  •   
  • '\u000B',U + 000B垂直制表。
  •   
  • '\f',U + 000C FORM FEED。
  •   
  • '\r',U + 000D CARRIAGE RETURN。
  •   
  • '\u001C',U + 001C FILE SEPARATOR。
  •   
  • '\u001D',U + 001D GROUP SEPARATOR。
  •   
  • '\u001E',U + 001E RECORD SEPARATOR。
  •   
  • '\u001F',U + 001F UNIT SEPARATOR。
  •   

如果我没有弄错 - 或者我可能只是没有正确阅读 - String.trim()应该删除Character.isWhiteSpace()正在检查的任何字符。所有人都看到高于'\u0020'

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

  1. 是否有一个字符串会使isEmptyisBlank在测试用例中表现不同?
  2. 假设没有,是否还有其他考虑因素,我应该选择isBlank而不使用isEmpty
  3. 对于那些对实际运行测试感兴趣的人,这里有方法和单元测试。

    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。谢谢@Dukeling。
    • 选择标准isBlank()的性能相关原因。谢谢@devconsole。
    • @nhahtdh的全面解释。谢了哥们。

8 个答案:

答案 0 :(得分:32)

  

是否有一个字符串会使isEmptyisBlank在测试用例中表现不同?

请注意,Character.isWhitespace可识别Unicode字符,并返回{NULL}空格字符的true

  

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

     
      
  • 它是一个Unicode空格字符(SPACE_SEPARATORLINE_SEPARATORPARAGRAPH_SEPARATOR),但也不是一个不间断的空格('\u00A0',{{ 1}},'\u2007')。

  •   
  • '\u202F'

  •   

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

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

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

  • "\002"等同于isEmpty()
  • .matches("[\\x00-\\x20]*")等同于isBlank()

.matches("\\p{javaWhitespace}*")isEmpty()方法都允许isBlank()字符串引用,因此它不完全等同于正则表达式解决方案,但将它放在一边,它是等效的。)< / p>

请注意null,顾名思义,是用于访问\p{javaWhitespace}方法定义的字符类的特定于Java的语法。

  

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

这取决于。但是,我认为上述部分的解释应该足以让您做出决定。总结差异:

  • isEmpty如果字符串只包含控制字符 1 在U + 0020和空格字符(U + 0020)

  • isEmpty()如果字符串只包含由isBlank方法定义的空白字符,则会认为该字符串为空,其中包含Unicode空白字符。

1 Character.isWhitespace处还有一个控制字符,不会被U+007F DELETE方法修剪。

答案 1 :(得分:25)

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

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

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

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


<强>更新

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

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

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

答案 2 :(得分:14)

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

答案 3 :(得分:4)

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

答案 4 :(得分: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 false 2 false 3 true

这里的前两个场景返回false(即null和empty),第三个场景返回true

答案 5 :(得分: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}
<%} %>

答案 6 :(得分: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"));
}

答案 7 :(得分:0)

使用Java 8,您还可以使用可选功能进行过滤。要检查字符串是否为空,代码是纯Java SE而没有其他库。 以下代码说明了isBlank()实现。

String.trim()行为

.toString()

StringUtils.isBlank()行为

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