Java поток, а l oop предупреждения об аномалии от PMD - PullRequest
0 голосов
/ 18 июня 2020

В следующем коде я создаю новый идентификатор, проверяю, существует ли он, и возвращаю его, если он уникален:

private String generateNewId(List<Item> items) {
    do {
        String newId = ... // generateNewId from another method
        if (items.stream.noneMatch(i -> i.getId().equals(newId))) {
            return newId;
        }
    } while(true);
}

Однако я получаю аномалии PMD:

  • Обнаружена аномалия DD для переменной newId
  • Обнаружена аномалия DU для переменной newId

Из документации PMD:

  1. DU - Аномалия: недавно определенная переменная не определена. Эти аномалии могут появиться в обычном исходном тексте.
  2. DD - Аномалия: переопределяется недавно определенная переменная. Это зловещее, но не обязательно ошибкой.

Я попытался переместить newId переменную за пределы l oop, но потом получил ошибку: Используемые переменные в лямбда-выражении должно быть final или фактически final .

Как мне провести рефакторинг моего кода, чтобы избавиться от этих аномалий? Или мне следует подавить эти предупреждения как ложные срабатывания?

1 Ответ

1 голос
/ 20 июня 2020

Вы видите аномалию DD, потому что переменная newId переопределяется в do { } while(true) l oop, когда условие if оценивается как ложное.

Аномалия DU, однако, является ложноположительным , Думаю. В этом случае newId всегда используется хотя бы один раз:

  • если список элементов пуст, то возвращается newId
  • , если список элементов не пуст , тогда newId используется в закрытии nonMatch

Но это то, что PMD не может понять, потому что он не знает семантику noneMatch. Если вы замените noneMatch на anyMatch, это будет настоящая аномалия DU.

Аномалии DD и DU часто трудно исправить, потому что они указывают на проблемы дизайна на более высоком уровне. В этом случае проблема заключается не непосредственно в самой переменной newId, а в использовании do { } while(true), что может привести к бесконечному l oop, потому что вы игнорируете случай, когда вы не можете сгенерировать новый уникальный идентификатор.

Один из способов решить эту проблему - решить эту проблему:

    private String generateNewId(List<Item> items) {
        return Stream.generate(this::getRandomId)
                     .limit(100)
                     .filter(id -> isNew(id, items))
                     .findAny()
                     .orElseThrow(() -> new NoSuchElementException("Failed to generate unique id."));
    }

    private String getRandomId() {
        return "4";  // chosen by fair dice roll.
                     // guaranteed to be random.
    }

    private boolean isNew(String id, List<Item> items) {
        return items.stream().noneMatch(item -> id.equals(item.getId()));
    }

Это решение решает проблему бесконечного l oop, пытаясь сгенерировать новый идентификатор не более 100 раз и генерируя исключение, если оно терпит неудачу. В зависимости от вашей ситуации вы можете выбрать другой лимит.

...