Stream.dropWhile() не возвращает правильное значение в двух разных значениях

Я пытаюсь изучить новые функции в Java-9. Я узнаю о методе dropWhile Stream, но он возвращает разные значения в двух разных сценариях. Вот мой код

package src.module;

import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.List;

public class Test {

    public static void main(String[] args) {

        String s[] = new String[3];
        s[0] = "Hello";
        s[1] = "";
        s[2] = "World";
        List<String> value = Stream.of(s).dropWhile(a -> a.isEmpty()).collect(Collectors.toList());

        System.out.println(value);

        List<String> values = Stream.of("a", "b", "c", "", "e", "f").dropWhile(d -> !d.isEmpty())
                .collect(Collectors.toList());
        System.out.println(values);

    }
}

Вот ответ, что я получаю

[Hello, , World]
[, e, f]

Я думаю, что в первом условии он должен печатать [,World]. Заранее спасибо.


person Harsh Kumrawat    schedule 02.10.2018    source источник
comment
в чем я сомневаюсь в первом условии, он возвращает только приветствие, а два левых значения следует отбросить. Не так ли?   -  person Harsh Kumrawat    schedule 02.10.2018


Ответы (4)


Метод dropWhile, представленный в Java 9, удалит самый длинный начальный набор элементов, соответствующих предикату.

Возвращает, если этот поток упорядочен, поток, состоящий из оставшихся элементов этого потока после отбрасывания самого длинного префикса элементов, соответствующих заданному предикату.

Поскольку ваше условие состоит в том, что элемент пуст, а первый элемент не пуст, ничего не удаляется, оставляя ["Hello", "", "World"] нетронутым.

В конце, когда вы вызываете dropWhile с противоположным условием, не является пустым, первые 3 элемента совпадают и удаляются, оставляя ["", "e", "f"], которые являются оставшимися элементами.

Это ожидаемое поведение.

person rgettman    schedule 02.10.2018
comment
в чем я сомневаюсь в первом условии, он возвращает только приветствие, а два левых значения следует отбросить. Не так ли? - person Harsh Kumrawat; 02.10.2018
comment
@HarshKumrawat ничего не следует отбрасывать, поскольку самый длинный префикс элементов, соответствующих данному предикату, пуст. - person Eran; 02.10.2018

Ваше первое условие говорит об отбрасывании элементов до тех пор, пока не будет найден непустой элемент. Второе условие говорит об отбрасывании элементов до тех пор, пока не будет найден пустой элемент. Добавить '!' к вашему первому условию, чтобы получить прогнозируемый результат.

person x sylver    schedule 02.10.2018
comment
в чем я сомневаюсь в первом условии, он возвращает только приветствие, а два левых значения следует отбросить. Не так ли? - person Harsh Kumrawat; 02.10.2018
comment
'dropWhile' работает до тех пор, пока заданное условие истинно. Он останавливается, когда условие ложно. В первом цикле условие ложно с самого начала. Во втором цикле верно для 2-х элементов потока. - person x sylver; 02.10.2018
comment
@HarshKumrawat Он говорит, что вы ставите a.isEmpty(), когда хотите !a.isEmpty(). Вот почему результат не такой, как вы ожидали. - person Sean Van Gorder; 02.10.2018

Javadoc dropWhile указывает:

Возвращает, если этот поток упорядочен, поток, состоящий из оставшихся элементов этого потока после отбрасывания самого длинного префикса элементов, соответствующих заданному предикату.

В первом фрагменте первый элемент Stream не удовлетворяет a -> a.isEmpty(), поэтому элементы не отбрасываются.

Во втором фрагменте первые 3 элемента в Stream удовлетворяют d -> !d.isEmpty(), поэтому эти 3 элемента отбрасываются, оставляя "", "e" и "f".

person Eran    schedule 02.10.2018
comment
в чем я сомневаюсь в первом условии, он возвращает только приветствие, а два левых значения следует отбросить. Не так ли? - person Harsh Kumrawat; 02.10.2018
comment
@HarshKumrawat Ничего не следует отбрасывать, поскольку самый длинный префикс элементов, соответствующих данному предикату, пуст. - person rgettman; 02.10.2018

Для лучшего понимания алгоритма можно попробовать заменить Stream версию:

List<String> value = Stream.of(s).dropWhile(String::isEmpty).collect(Collectors.toList());

с классической петлей for:

List<String> value = new ArrayList<>();
boolean dropping = true;

for (int i = 0; i < s.length; i++) {
    String str = s[i];
    if (dropping) {
        if (str.isEmpty()) {
            continue;
        }
        dropping = false;
    }
    value.add(str);
}
person Oleksandr Pyrohov    schedule 02.10.2018
comment
Поскольку я изучаю функцию потока, я хочу использовать только методы потока. Спасибо за ответ. - person Harsh Kumrawat; 02.10.2018
comment
Это просто взгляд под другим углом :) ... Продолжайте учиться! - person Oleksandr Pyrohov; 02.10.2018