Бизнес-запрос заключается в том, что я создаю List<ResponsePOJO>
из List<RequestPOJO>
. Это кажется достаточно простым.
Запрос на самом деле нуждается в некоторой ( больше ) обработке, то есть мне нужно сохранить пару параметров, а затем для каждого элемента выполнить запрос к CassandraMicroservice, который возвращает * 1008. *. Каждый элемент этого <List<CassandraPOJO>
имеет свой собственный List<DataPOJO>
, который должен попадать в категорию, представленную некоторыми специфическими c характеристиками в List<ResponsePOJO>
. По сути, для каждого элемента в List<RequestPOJO>
я строю List<List<DataPOJO>>
, с которым нужно разобраться. К сожалению, все застряло так, как есть Я не могу изменить архитектуру .
Короче, моя проблема , что я не могу найти простой createOrUpdate
на Map
. Я попытался сделать updateOrCreate
типа BiFunction
. Я думаю, этого должно быть достаточно, чтобы сделать что-то вроде BiFunction, Map>, которое должно выглядеть следующим образом ( псевдокод ):
private BiFunction<ResponsePOJO, Map<Integer, ResponsePOJO>, Map<Integer, ResponsePOJO>> updateOrCreate(?*) {
return (newValue, currentResult) -> {
if (currentResult.contains(newValue))
currentResult.updateParams(newValue);
else
currentResult.put(newValue);
return currentResult;
};
}
? * Я заметил, что вызов BiFunction не имеет параметров, откуда он знает, к какому типу относятся его параметры? ( не мой главный вопрос , но я думаю, что одной из причин моей проблемы является отсутствие истинного понимания BiFunction
вместе с Map.compute
)
(почти) полный фрагмент кода:
// the POJOs, using lombok (anotations skipped)
public class RequestPOJO {
private Long id;
private Long idEntity;
private Long idInventory;
// some are omitted for brevity
}
@Builder(toBuilder = true)
public class ResponsePOJO {
private Integer id;
private Long noInventory;
private String nameSpecies;
private Double g1;
private Double g2;
private Double g3;
// some are omitted for brevity
public void updateParams(ResponsePOJO resp) {
// only these fields need updating, because of business logic
this.g1 += resp.getG1();
this.g2 += resp.getG2();
this.g3 += resp.getG3();
}
}
public class CassandraPOJO {
private Long id;
private List<DataPOJO> detailsDataPojo;
private Long noInventory;
// some are omitted for brevity
}
public class DataPOJO {
private Long idSpecies;
private Long idQualityClass;
private Double height;
private Double diameter;
private Double noCount;
// some are omitted for brevity
}
// the business logic
public List<ResponsePOJO> compute(List<RequestPOJO> requestPojoList, List<SpeciesPOJO>speciesList) {
List<ResponsePOJO> responseList = new ArrayList<>();
for (RequestPOJO requestPojo : requestPojoList) {
Long idEntity = requestPojo.getIdEntity();
Long noInventory = requestPojo.getIdInventory(); // yes I know this is wrong, stick to the question
List<CassandraPOJO> res = cassandraMicroservice.getByIdEntityFilteredByNoInventory(idEntity, noInventory);
res.stream().forEach(dar -> {
Map<Long, List<DataPOJO>> listDataPojoBySpeciesId =
dar.getDetailsDataPojo().stream().collect(
Collectors.groupingBy(DataPOJO::getIdSpecies, Collectors.toList())
);
responseList.addAll(
classifyDataPojo(listDataPojoBySpeciesId, speciesList, dar.getNoInventory())
);
});
}
Comparator<ResponsePOJO> compareResponsePojo = Comparator.comparing(ResponsePOJO::getNameSpecies);
return responseList.stream()
.sorted(compareResponsePojo).collect(Collectors.toList());
}
private List<ResponsePOJO> classifyDataPojo(Map<Long, List<DataPOJO>> listDataPojoBySpeciesId, List<SpeciesPOJO> speciesList, Long noInventory) {
Map<Integer, ResponsePOJO> result = new HashMap();
for (Long speciesId : listDataPojoBySpeciesId.keySet()) {
String nameSpecies = speciesList.stream().filter(s -> s.getIdSpecies() == speciesId).findFirst().get().getNameSpecies(); // it's guaranteed to be found
for (DataPOJO dataP : listDataPojoBySpeciesId.get(speciesId)) {
Double volumeUnit = getVolumeUnit(dataP);
Double equivalenceCoefficient = getEquivalentClass(dataP, speciesList);
CustomTypeEnum customType = getCustomType(speciesList, dataP.getDiameter, speciesId);
resp = ResponsePOJO.builder()
.noInventory(noInventory)
.nameSpecies(nameSpecies)
.build();
switch (customType) {
case G1:
resp.setG1(volumeUnit * equivalenceCoefficient * dataP.getNoCount());
break;
case G2:
resp.setG2(volumeUnit * equivalenceCoefficient * dataP.getNoCount());
break;
case G3:
resp.setG3(volumeUnit * equivalenceCoefficient * dataP.getNoCount());
break;
default:
break;
}
}
int diameter = ComputeUtil.getDiamenterClass(resp.getDiameter());
// doesn't compile, it says Wrong 2nd argument type. Found: BiFunction<ResponsePOJO, Map<Integer, ResponsePOJO>, Map<Integer,ResponsePOJO>> Required: BiFunction<? super Integer,? super ResponsePOJO,? extends ResponsePOJO>
result.compute(diameter, updateOrCreate());
// I have fiddled with reduce and merge but to no avail
// result.values().stream().reduce(new ArrayList<>(), updateOrCreate(), combiningFunction());
// result.merge(diameter, update())
}
return result.values().stream().collect(Collectors.toList());
}
Я выбрал Map, потому что я хочу, чтобы он был максимально быстрым, этот метод compute(...)
вызывается довольно часто, и я не хочу искать по всему списку ответов каждый раз, когда мне нужно что-то обновить. Я не хочу менять POJO, особенно CassandraPOJO
, который имеет DataPOJO
.
. Как вы можете видеть, это смесь как классических for
, так и java8 stream
. Я намереваюсь изменить весь код в соответствии с java8, но мне понадобилось немало времени, чтобы написать этот (сложный, сложный, понятный) код.
Я твердо убежден, что существует более простое решение, но я не могу понять это самостоятельно.