63

I am trying to check if a Java String is not null, not empty and not whitespace.

In my mind, this code should have been quite up for the job.

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

As per documentation, String.trim() should work thus:

Returns a copy of the string, with leading and trailing whitespace omitted.

If this String object represents an empty character sequence, or the first and last characters of character sequence represented by this String object both have codes greater than '\u0020' (the space character), then a reference to this String object is returned.

However, apache/commons/lang/StringUtils.java does it a little differently.

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

As per documentation, Character.isWhitespace():

Determines if the specified character is white space according to Java. A character is a Java whitespace character if and only if it satisfies one of the following criteria:

  • It is a Unicode space character (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) but is not also a non-breaking space ('\u00A0', '\u2007', '\u202F').
  • It is '\t', U+0009 HORIZONTAL TABULATION.
  • It is '\n', U+000A LINE FEED.
  • It is '\u000B', U+000B VERTICAL TABULATION.
  • It is '\f', U+000C FORM FEED.
  • It is '\r', U+000D CARRIAGE RETURN.
  • It is '\u001C', U+001C FILE SEPARATOR.
  • It is '\u001D', U+001D GROUP SEPARATOR.
  • It is '\u001E', U+001E RECORD SEPARATOR.
  • It is '\u001F', U+001F UNIT SEPARATOR.

If I am not mistaken - or might be I am just not reading it correctly - the String.trim() should take away any of the characters that are being checked by Character.isWhiteSpace(). All of them see to be above '\u0020'.

In this case, the simpler isEmpty function seems to be covering all the scenarios that the lengthier isBlank is covering.

  1. Is there a string that will make the isEmpty and isBlank behave differently in a test case?
  2. Assuming there are none, is there any other consideration because of which I should choose isBlank and not use isEmpty?

For those interested in actually running a test, here are the methods and unit tests.

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

And unit tests

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

Update: It was a really interesting discussion - and this is why I love Stack Overflow and the folks here. By the way, coming back to the question, we got:

  • A program showing which all characters will make the behave differently. The code is at https://ideone.com/ELY5Wv. Thanks @Dukeling.
  • A performance related reason for choosing the standard isBlank(). Thanks @devconsole.
  • A comprehensive explanation by @nhahtdh. Thanks mate.
5
  • 9
    +1 for formatting and clarity. Commented May 6, 2013 at 8:26
  • Note that with both functions, null is accepted and will return true. Commented May 6, 2013 at 8:29
  • @Anirudh no, the && is correct Commented May 6, 2013 at 8:35
  • @Thrakbad ohh..yes you are right Commented May 6, 2013 at 8:37
  • 1
    I am wondering why you don't write isEmpty simply as public static boolean isEmpty(String s) { return (s == null) || s.trim().isEmpty(); } . I am always somewhat confused if someone uses a whole if statement to express just a negation. Commented May 14, 2013 at 18:57

8 Answers 8

32

Is there a string that will make the isEmpty and isBlank behave differently in a test case?

Note that Character.isWhitespace can recognize Unicode characters and return true for Unicode whitespace characters.

Determines if the specified character is white space according to Java. A character is a Java whitespace character if and only if it satisfies one of the following criteria:

  • It is a Unicode space character (SPACE_SEPARATOR, LINE_SEPARATOR, or PARAGRAPH_SEPARATOR) but is not also a non-breaking space ('\u00A0', '\u2007', '\u202F').

  • [...]

On the other hand, trim() method would trim all control characters whose code points are below U+0020 and the space character (U+0020).

Therefore, the two methods would behave differently at presence of a Unicode whitespace character. For example: "\u2008". Or when the string contains control characters that are not consider whitespace by Character.isWhitespace method. For example: "\002".

If you were to write a regular expression to do this (which is slower than doing a loop through the string and check):

  • isEmpty() would be equivalent to .matches("[\\x00-\\x20]*")
  • isBlank() would be equivalent to .matches("\\p{javaWhitespace}*")

(The isEmpty() and isBlank() method both allow for null String reference, so it is not exactly equivalent to the regex solution, but putting that aside, it is equivalent).

Note that \p{javaWhitespace}, as its name implied, is Java-specific syntax to access the character class defined by Character.isWhitespace method.

Assuming there are none, is there any other consideration because of which I should choose isBlank and not use isEmpty?

It depends. However, I think the explanation in the part above should be sufficient for you to decide. To sum up the difference:

  • isEmpty() will consider the string is empty if it contains only control characters1 below U+0020 and space character (U+0020)

  • isBlank will consider the string is empty if it contains only whitespace characters as defined by Character.isWhitespace method, which includes Unicode whitespace characters.

1 There is also the control character at U+007F DELETE, which is not trimmed by trim() method.

Sign up to request clarification or add additional context in comments.

Comments

25

The purpose of the two standard methods is to distinguish between this two cases:

org.apache.common.lang.StringUtils.isBlank(" ") (will return true).

org.apache.common.lang.StringUtils.isEmpty(" ") (will return false).

Your custom implementation of isEmpty() will return true.


UPDATE:

  • org.apache.common.lang.StringUtils.isEmpty() is used to find if the String is length 0 or null.

  • org.apache.common.lang.StringUtils.isBlank() takes it a step forward. It not only checks if the String is length 0 or null, but also checks if it is only a whitespace string.

In your case, you're trimming the String in your isEmpty method. The only difference that can occur now can't occur (the case you gives it " ") because you're trimming it (Removing the trailing whitespace - which is in this case is like removing all spaces).

2 Comments

I think everybody is confused. Listen up. Maroun Maroun is right with the standard functions. But, the OP decided to write the function himself. Please note that normally, isEmpty would return false, but now the test is: s.trim().length() > 0. Trimming s will remove all the whitespaces leading and trailing the string. Therefore, " " becomes "". This length == 0. Now it will return false!
14

I would choose isBlank() over isEmpty() because trim() creates a new String object that has to be garbage collected later. isBlank() on the other hand does not create any objects.

8 Comments

That sounds like a good reason. However, think about the performance also. If the string was long, it would iterate over each character. Whereas, just by calling trim you could have made a short work of this.
isBlank() immediately returns as soon as it encounters the first non-whitespace character. The only problem would be a long string with a single non-whitespace character at the end but then trim() would also have to iterate over the characters internally.
@partha trim would not iterate over the whole string, just the first N+1 and last M+1 chars, where N and M are whitespace chars.
@Dariusz Neither would isBlank for that matter, which would actually do less iterating than trim would for non-empty strings with trailing white-space.
@devconsole No internal sharing happens in String as of OpenJDK 7 Update 6. You should reconsider your definition of "decent Java implementation".
|
4

You could take a look at JSR 303 Bean Validtion wich contains the Annotatinos @NotEmpty and @NotNull. Bean Validation is cool because you can seperate validation issues from the original intend of the method.

1 Comment

I am familiar with JSR 303 and yes they are quite cool. My question was more about understanding what goes on behind the scenes. I guess when I actually need to make this validation, I could wrap either of these methods in discussion under the wraps of JSR 303, with custom annotations. But that was not the intent of the question. I was more interested in finding if there was a functional and / or peformance difference between the two implementation.
1

Why can't you simply use a nested ternary operator to achieve this.Please look into the sample code 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)); }

and the output is as follows

1 false 2 false 3 true

here the 1st 2 scenarios returns false (i.e null and empty)and the 3rd scenario returns true

Comments

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}
<%} %>

Comments

0

This simple code will do enough:

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

And the unit tests:

@Test
public void testIsNullOrEmpty() {
    assertEquals(true, AcdsUtils.isNullOrEmpty(""));
    assertEquals(true, AcdsUtils.isNullOrEmpty((String) null));
    assertEquals(false, AcdsUtils.isNullOrEmpty("lol    "));
    assertEquals(false, AcdsUtils.isNullOrEmpty("HallO"));
}

Comments

0

With Java 8, you could also use the Optional capability with filtering. To check if a string is blank, the code is pure Java SE without additional library. The following code illustre a isBlank() implementation.

String.trim() behaviour

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

StringUtils.isBlank() behaviour

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.