Почему из этого потока Java не отфильтровываются пустые строки? - PullRequest
2 голосов
/ 06 января 2020

У меня есть потоковая операция (Java 8), которая предназначена для разбивки набора строк на двойные и получения суммы. Некоторые строки пусты, но я не верю, что они пустые. Я добавил операцию filter, чтобы отфильтровать пустые, прежде чем они достигнут Double.parseDouble(), где они могут вызвать ошибку, но фильтр, похоже, не работает.

Мой код:

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

Это JSP, а JSP не компилируется. Согласно странице ошибки, исключение возникает в последней строке (.reduce(0D,Double::sum);), но «root причина» - это «java.lang.NumberFormatException: empty String» - Double.parseDouble() обнаруживает пустые строки.

Я пробовал несколько перестановок операции filter, в том числе некоторые, которые проверяли на нулевое значение, и некоторые, которые проверяли !s.equals("") и тому подобное. Я добавил операции peek для отладки, и стало ясно, что пустая строка печатается как до , так и после filter строки.

Что такое Я делаю не так? Есть ли лучший способ отфильтровать значения, которые не могут быть проанализированы с удвоениями?

Ответы [ 3 ]

2 голосов
/ 07 января 2020

Строка с пробелами, технически не пустая, вызывает исключение с сообщением «пустая строка». Как указал другой автор, решение состоит в том, чтобы сначала обрезать входную строку.

Эта путаница является результатом неудачной ошибки документации в sun.misc.FloatingDecimal.readJavaFormatString, которая косвенно вызывается Double.parseDouble. Хотя семантика String#empty равна

Возвращает true тогда и только тогда, когда length() равно 0.

реализация readJavaFormatString фактически обрезает входную строку сначала , затем вычисляет длину и выдает NumberFormatException с (очень вводящим в заблуждение) сообщением "пустая строка":

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

Это можно легко увидеть, выполнив:

Double.parseDouble("   ");
2 голосов
/ 06 января 2020

Может быть, это пробелы, вы можете trim() сначала строку и затем проверить, если она пуста, также удалить пробельные строки, такие как:

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

Если вы используете java 11, вы можете используйте String.isBlank() в вашем фильтре вместо isEmpty (). isEmpty() смотрит на длину струны. isBlank ищет пробелы.

0 голосов
/ 07 января 2020

Вы также можете использовать функцию Apache StringUtils.isNotBlank . Она позаботится как о пустых, так и о пустых строках.

https://commons.apache.org/proper/commons-lang/javadocs/api-3.3/org/apache/commons/lang3/StringUtils.html#isNotBlank (java .lang.CharSequence)

double myTotal= Stream.of("","10.00","20.22","  ")
                //.map(myObject::getAmount)
                .peek( s -> System.out.println("before filter: " + s) )
                .filter(StringUtils::isNotBlank)
                .peek( s -> System.out.println("after filter: " + s) )
                .mapToDouble(Double::parseDouble)
                .reduce(0D,Double::sum);

Выход:

до фильтра:

до фильтра: 10,00

после фильтра: 10,00

до фильтра: 20,22

после фильтра: 20,22

до фильтра:

30,22

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...