Необязательные потоки Java с нулевой проверкой двух элементов - PullRequest
1 голос
/ 06 ноября 2019

У меня есть следующий код, который работает на два значения, а именно. List из String и String. И List, и String могут быть null.

List<String> myStringList = getMyStringList(); // may return null
String myString = "abc"; // may be null

List<String> finalStringList = Optional.ofNullable(myStringList)
            .map(strings -> strings.stream()
                    .filter(obj -> StringUtils.isEmpty(myString)
                            || myString.equals(obj))
                    .collect(Collectors.toList()))
            .orElseGet(ArrayList::new);

Идея такова: если myStringList равно null, то в результате будет пусто ArrayList. Если myString равно null, вернуть myStringList как есть. Если myString не равно нулю, выполните цикл по списку и верните все элементы, соответствующие myString.

Проблема в том, что с решением, приведенным выше, я все еще перебираю весь список (strings.stream), даже когда myString ноль.

Предполагая, что myStringList очень большой, как я могу избежать зацикливания списка для случая, когда myString равен нулю?

То есть

1) сделатьпроверка нуля в списке. Если ноль, вернуть новый пустой список.

2) сделать проверку на ноль myString. Если ноль, вернуть список как БЕЗ ЗАПУСКА.

3) если myString не ноль, перебрать список и вернуть отфильтрованный список.

Ответы [ 4 ]

2 голосов
/ 06 ноября 2019

Вы можете использовать троичную форму, такую ​​как

List<String> finalStringList = myString == null ?
        Collections.emptyList()
        : Optional.ofNullable(myStringList)
        .map(strings -> strings.stream()
                .filter(obj -> StringUtils.isEmpty(myString)
                        || myString.equals(obj))
                .collect(Collectors.toList()))
        .orElseGet(ArrayList::new);

или базовую if и по умолчанию использовать пустой список. Мол,

List<String> finalStringList = Collections.emptyList();
if (myString != null) {
    finalStringList = Optional.ofNullable(myStringList)
            .map(strings -> strings.stream()
                    .filter(obj -> StringUtils.isEmpty(myString)
                            || myString.equals(obj))
                    .collect(Collectors.toList()))
            .orElseGet(ArrayList::new);
}
1 голос
/ 06 ноября 2019

Это может работать для вас (с Java 9 +):

List<String> result2 = Optional.ofNullable(myString)
  .filter(Objects::nonNull)
  .map(mystr -> Optional.ofNullable(myStringList)
                        .filter(Objects::nonNull)
                        .or(() -> Optional.of(new ArrayList<>()))
                        .stream()
                        .flatMap(List::stream)
                        .filter(mystr::equals)
                        .collect(Collectors.toList())) //ArrayList not guaranteed
    .orElse(myStringList);

Если вы используете Java 8, должно работать следующее, но читать немного сложнее:

List<String> result = Optional.ofNullable(myString)
  .filter(Objects::nonNull)
  .map(mystr -> Optional.ofNullable(myStringList)
                .filter(Objects::nonNull)
                .map(list -> list.stream()
                            .filter(mystr::equals)
                            .collect(Collectors.toList()))
                .orElseGet(ArrayList::new))
  .orElse(myStringList);
0 голосов
/ 10 ноября 2019

Лично я думаю, что код if-else будет гораздо более читабельным / поддерживаемым / эффективным:

if (myStringList == null || myStringList.size() == 0) {
    return Collections.emptyList();
} else if (StringUtils.isEmpty(myString)) {
    return new ArrayList<>(myStringList); // or return myStringList;
} else {
    return myStringList.stream().filter(e -> myString.equals(e))
                                .collect(Collectors.toList());
}

Хорошо, если вы действительно хотите избежать написания нескольких строк кода, попробуйте мою библиотеку: abacus-util

return N.isNullOrEmpty(myString) ? N.newArrayList(myStringList) 
                                 : N.filter(myStringList, e -> myString.equals(e));
0 голосов
/ 06 ноября 2019

Другое решение

List<String> myStringList = Arrays.asList("abc", "aef"); // may return null
String myString = "abc"; // may be null

Map<Predicate, Supplier<List<String>>> predicateMap = Map.of(
      (v) -> myStringList == null, () -> new ArrayList<>(), // do a null check on the list. If null, return a new empty list.
      (v) -> myString == null, () -> myStringList, // do a null check on myString. If null, return the list as is WITHOUT LOOPING.
      (v) -> true, () -> myStringList.stream() // if myString is not null, loop through the list and return the filtered list.
                .filter(myString::equals)
                .collect(Collectors.toList())
      );
List<String> outputList = predicateMap.entrySet().stream()
      .filter(p -> p.getKey().test(null))
      .findFirst().get().getValue().get();

System.out.println(outputList);
...