Search code examples
javajava-streamnumberformatexception

Why aren't empty strings filtered out of this Java stream?


I have a stream operation (Java 8) that is meant to parse a bunch of strings into doubles and take a sum. Some of the strings are empty, but I don't believe any are null. I've added a filter operation to filter the empty ones out before they reach Double.parseDouble() where they might cause an error, but the filter doesn't seem to work.

My code:

double myTotal= myObjectList.stream()
    .map(myObject::getAmount)
    .peek( s -> System.out.println("before filter: " + s) )
    .filter( s -> !s.isEmpty() )
    .peek( s -> System.out.println("after filter: " + s) )
    .mapToDouble(Double::parseDouble)
    .reduce(0D,Double::sum);

This is in a JSP, and the JSP fails to compile. According to the error page, the exception occurs in the last line (.reduce(0D,Double::sum);), but the "root cause" is a "java.lang.NumberFormatException: empty String" -- Double.parseDouble() is encountering empty strings.

I have tried several permutations of the filter operation, including some that checked for null and some that checked !s.equals("") and the like. I added the peek operations for debugging and it is clear that an empty string is being printed both before and after the filter line.

What am I doing wrong? Is there a better way to filter out values that can't be parsed to doubles?


Solution

  • String with white spaces, technically not empty, cause an exception to be raised with the message "empty string". As another poster pointed out, the solution is to trim the input string first.

    This confusion is the result of an unfortunate documentation bug in sun.misc.FloatingDecimal.readJavaFormatString which is indirectly called by Double.parseDouble. Although the semantics of String#empty is

    Returns true if, and only if, length() is 0.

    the implementation of readJavaFormatString actually trims the input string first, then computes the length, and throws the NumberFormatException with the (very misleading) message "empty string":

    in = in.trim(); // don't fool around with white space.
                    // throws NullPointerException if null 
    int len = in.length();
    if ( len == 0 ) {
        throw new NumberFormatException("empty String");
    }
    

    This can be readily observed by executing:

    Double.parseDouble("   ");