Можно, конечно, определить два списка, один со всеми допустимыми типами и один с предпочтительными типами.
Однако, здесь есть другой подход. Определите один список, или фактически, Map
, с ключами, являющимися допустимыми типами, и логическими значениями, определяющими, является ли тип предпочтительным.
Map<String, Boolean> validTypes = ImmutableMap.of(
"TypeA", false,
"TypeB", false,
"TypeC", true
);
Использование AtomicReference
Один из следующих вариантов:
AtomicReference<A> ref = new AtomicReference<>();
listOfAs.stream()
.filter(t -> validTypes.containsKey(t.getType()))
.anyMatch(t -> validTypes.get(ref.updateAndGet(u -> t).getType()));
AtomicReference
теперь содержит предпочтительный A
, если доступен, или другой допустимый A
, или, если поток пустой, то он содержит null
. Эта потоковая операция замыкается, если найден A
с предпочтительным типом.
Недостатком этой опции является то, что она создает побочные эффекты , , которые не поощряются .
Использование distinct()
Еще одно предложение будет следующим. Он использует ту же структуру карты, используя логическое значение, чтобы указать, какие значения являются предпочтительными. Однако не создает побочных эффектов .
Map<Boolean, A> map = listOfAs.stream()
.filter(t -> validTypes.containsKey(t.getType()))
.map(t -> new Carrier<>(validTypes.get(t.getType()), t))
.distinct()
.limit(2)
.collect(Collectors.toMap(Carrier::getKey, Carrier::getValue));
Работает следующим образом.
filter
удаляет любой элемент, который не является допустимым типом.
- Затем каждый элемент сопоставляется с
Carrier<Boolean, A>
экземпляром. Carrier
- это Map.Entry<K, V>
, который реализует свои методы equals
и hashCode
, относящиеся только к key
; value
не имеет значения. Это необходимо для следующего шага,
distinct()
, который отбрасывает любой дублирующий элемент. Таким образом, будет найден только один предпочтительный тип и только один допустимый тип.
- Мы ограничиваем поток двумя элементами, по одному для каждого логического значения. Это потому, что поток, который является ленивым, перестает оценивать после того, как оба логических значения найдены.
- Наконец, мы собираем элементы Carrier в карту.
Карта теперь содержит следующие элементы:
Boolean.TRUE
=> A
с предпочтительным типом
Boolean.FALSE
=> A
с допустимым типом
Получить соответствующий элемент, используя
A a = map.getOrDefault(true, map.get(false)); // null if not found