在Java中检查非空,非空string
我正在试图检查一个Javastring是不是null
,不是空的,而不是空白。
在我看来,这个代码应该已经很适合这份工作了。
public static boolean isEmpty(String s) { if ((s != null) && (s.trim().length() > 0)) return false; else return true; }
根据文档, String.trim()
应该这样工作:
返回string的副本,省略前导和尾随空白。
如果这个
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_SEPARATOR
或PARAGRAPH_SEPARATOR
),但也不是一个非'\u00A0'
空间('\u00A0'
,'\u2007'
,'\u202F'
)。- 这是
'\t'
,U + 0009水平制表。- 这是
'\n'
,U + 000A线路馈送。- U + 000B垂直制表
'\u000B'
是'\u000B'
。- 这是
'\f'
,U + 000C FORM FEED。- 它是
'\r'
,U + 000D装运返回。- U + 001C FILE SEPARATOR是
'\u001C'
。- U + 001D GROUP SEPARATOR是
'\u001D'
。- U + 001E RECORD SEPARATOR是
'\u001E'
。- U + 001F UNIT SEPARATOR是
'\u001F'
。
如果我没有弄错 – 或者可能是我只是没有正确地读取它 – String.trim()
应该带走由Character.isWhiteSpace()
检查的任何字符。 他们都'\u0020'
是'\u0020'
。
在这种情况下,简单的是isBlank
函数似乎覆盖了更长的isBlank
所覆盖的所有场景。
- 有没有一个string,将使
isEmpty
和isBlank
在testing用例中performance不同? - 假设没有,有没有其他的考虑,因为我应该select
isBlank
而不是使用isEmpty
?
对于那些对实际运行testing感兴趣的人,下面是方法和unit testing。
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; } }
和unit testing
@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) ; }
更新:这是一个非常有趣的讨论 – 这就是为什么我喜欢堆栈溢出和这里的人。 顺便说一句,回到这个问题,我们得到了:
- 一个程序,显示所有的字符会使行为有所不同。 该代码位于https://ideone.com/ELY5Wv 。 谢谢@Dukeling。
- select标准的性能相关原因是
isBlank()
。 谢谢@devconsole。 - @nhahtdh的全面解释。 谢了哥们。
有没有一个string,将使
isEmpty
和isBlank
在testing用例中performance不同?
请注意, Character.isWhitespace
可以识别Unicode字符,并为Unicode空白字符返回true
。
根据Java确定指定的字符是否为空格。 一个字符是一个Java空白字符,当且仅当它满足下列条件之一时:
它是一个Unicode空格字符(
SPACE_SEPARATOR
,LINE_SEPARATOR
或PARAGRAPH_SEPARATOR
),但也不是一个非'\u00A0'
空间('\u00A0'
,'\u2007'
,'\u202F'
)。
[...]
另一方面, trim()
方法将修剪代码点低于U + 0020和空格字符(U + 0020)的所有控制字符。
因此,这两种方法在Unicode空白字符的存在下会有不同的performance。 例如: "\u2008"
。 或者当string包含Character.isWhitespace
方法不考虑空格的控制字符时。 例如: "\002"
。
如果你要写一个正则expression式来做这件事(比通过string和检查循环要慢):
-
isEmpty()
将等同于.matches("[\\x00-\\x20]*")
-
isBlank()
将等同于.matches("\\p{javaWhitespace}*")
( isEmpty()
和isBlank()
方法都允许null
string引用,所以它不完全等同于正则expression式解决scheme,但放在一边,它是等价的)。
请注意, \p{javaWhitespace}
顾名思义是访问由Character.isWhitespace
方法定义的字符类的Java专用语法。
假设没有,有没有其他的考虑,因为我应该select
isBlank
而不是使用isEmpty
?
这取决于。 不过,我认为上面的解释应该足以让你自己决定。 总结一下:
-
如果只包含U + 0020和空格字符(U + 0020)以下的控制字符1,则
isEmpty()
将认为string为空 -
如果string仅包含由
Character.isWhitespace
方法(包括Unicode空白字符)定义的空白字符,则isBlank
会认为该string为空。
1 U+007F DELETE
还有一个控制字符,它不会被trim()
方法trim()
。
两种标准方法的目的是区分这两种情况:
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或空值,还检查它是否只是一个空白string。
你的情况,你正在修剪你的 isEmpty
方法中的string。 现在唯一不同的情况是不能发生的(你给它的情况" "
),因为你正在修剪它(删除尾部的空白 – 在这种情况下,就像删除所有空格一样)。
我会selectisBlank()
不是isEmpty()
因为trim()
会创build一个新的String对象,以后必须进行垃圾回收。 isBlank()
另一方面不会创build任何对象。
您可以看看JSR 303 Bean Validation(包含Annotatinos @NotEmpty
和@NotNull
。 Bean Validation是很酷的,因为你可以从方法的原始意图中分离validation问题。
为什么不能简单地使用一个嵌套的三元运算符来实现这一点。请查看示例代码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)); }
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真
这里前两个场景返回false(即空和空),第三个场景返回true
<% 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} <%} %>
这个简单的代码就足够了:
public static boolean isNullOrEmpty(String str) { return str == null || str.trim().equals(""); }
而unit testing:
@Test public void testIsNullOrEmpty() { assertEquals(true, AcdsUtils.isNullOrEmpty("")); assertEquals(true, AcdsUtils.isNullOrEmpty((String) null)); assertEquals(false, AcdsUtils.isNullOrEmpty("lol ")); assertEquals(false, AcdsUtils.isNullOrEmpty("HallO")); }
使用Java 8,您还可以使用可选function进行筛选。 为了检查一个string是否为空,代码是纯粹的Java SE,没有额外的库。 下面的代码illustre是一个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()