Как правило, при попытке рефакторинга кода вы должны сосредоточиться только на необходимых изменениях.
Только потому, что вы собираетесь использовать Stream API, нет причин загромождать код проверками на null
или пустыми массивами, которых нет в коде на основе цикла. Вы также не должны изменить BigInteger
на Integer
.
Тогда у вас есть два разных входа и вы хотите получить разные результаты от каждого из них, другими словами, у вас есть две совершенно разные операции. Хотя разумно рассмотреть возможность совместного использования общего кода между ними, после того как вы определили идентичный код, нет смысла пытаться выразить две совершенно разные операции как одну операцию.
Во-первых, давайте посмотрим, как мы это сделаем для традиционного цикла:
static void addToLists(String id, List<Integer> empIdList, List<BigInteger> dateList) {
String[] array = id.split("-");
dateList.add(new BigInteger(array[1]));
empIdList.add(Integer.valueOf(array[2]));
}
List<Integer> empIdAccepted = new ArrayList<>();
List<BigInteger> dateAccepted = new ArrayList<>();
for(EmployeeValidationAccepted acceptedDetail : acceptedDetails) {
addToLists(acceptedDetail.getId(), empIdAccepted, dateAccepted);
}
List<Integer> empIdRejected = new ArrayList<>();
List<BigInteger> dateRejected = new ArrayList<>();
for(EmployeeValidationRejected rejectedDetail : rejectedDetails) {
addToLists(rejectedDetail.getAd().getId(), empIdRejected, dateRejected);
}
Если мы хотим выразить то же, что и для потоковых операций, существует препятствие иметь два результата для каждой операции. До JDK 12 действительно потребовалось встроенное решение:
static Collector<String,?,Map.Entry<List<Integer>,List<BigInteger>>> idAndDate() {
return Collectors.mapping(s -> s.split("-"),
Collectors.teeing(
Collectors.mapping(a -> Integer.valueOf(a[2]), Collectors.toList()),
Collectors.mapping(a -> new BigInteger(a[1]), Collectors.toList()),
Map::entry));
}
Map.Entry<List<Integer>, List<BigInteger>> e;
e = Arrays.stream(acceptedDetails)
.map(EmployeeValidationAccepted::getId)
.collect(idAndDate());
List<Integer> empIdAccepted = e.getKey();
List<BigInteger> dateAccepted = e.getValue();
e = Arrays.stream(rejectedDetails)
.map(r -> r.getAd().getId())
.collect(idAndDate());
List<Integer> empIdRejected = e.getKey();
List<BigInteger> dateRejected = e.getValue();
Поскольку метод не может возвращать два значения, для их хранения используется Map.Entry
.
Чтобы использовать это решение с версиями Java до JDK 12, вы можете использовать реализацию, опубликованную в конце этого ответа . Тогда вам также придется заменить Map::entry
на AbstractMap.SimpleImmutableEntry::new
.
Или вы используете специальный сборщик, написанный для этой конкретной операции:
static Collector<String,?,Map.Entry<List<Integer>,List<BigInteger>>> idAndDate() {
return Collector.of(
() -> new AbstractMap.SimpleImmutableEntry<>(new ArrayList<>(), new ArrayList<>()),
(e,id) -> {
String[] array = id.split("-");
e.getValue().add(new BigInteger(array[1]));
e.getKey().add(Integer.valueOf(array[2]));
},
(e1, e2) -> {
e1.getKey().addAll(e2.getKey());
e1.getValue().addAll(e2.getValue());
return e1;
});
}
Другими словами, использование Stream API не всегда упрощает код.
Как последнее замечание, нам не нужно использовать Stream API для использования лямбда-выражений. Мы также можем использовать их для перемещения цикла в общий код.
static <T> void addToLists(T[] elements, Function<T,String> tToId,
List<Integer> empIdList, List<BigInteger> dateList) {
for(T t: elements) {
String[] array = tToId.apply(t).split("-");
dateList.add(new BigInteger(array[1]));
empIdList.add(Integer.valueOf(array[2]));
}
}
List<Integer> empIdAccepted = new ArrayList<>();
List<BigInteger> dateAccepted = new ArrayList<>();
addToLists(acceptedDetails, EmployeeValidationAccepted::getId, empIdAccepted, dateAccepted);
List<Integer> empIdRejected = new ArrayList<>();
List<BigInteger> dateRejected = new ArrayList<>();
addToLists(rejectedDetails, r -> r.getAd().getId(), empIdRejected, dateRejected);