For example, suppose you have a DTO like this:
/**
*Input with multiple filter conditions.
* <p>
** Actually, it may be more complicated or complex...
*/
@Data
class InputDto {
/**Conditions used for filters 1*/
private boolean conditions1;
/**Condition 2 used for filter*/
private boolean conditions2;
/**Condition 3 used for filter*/
private boolean conditions3;
/**Condition used for filter 4*/
private boolean conditions4;
/**Condition used for filter 5*/
private boolean conditions5;
// ...
}
If you want to aggregate this DTO list by condition, you will often write it as follows.
private void count(List<InputDto> inputs) {
//Number of cases when condition 1 is applied to the input
inputs.stream()
.filter(i -> i.isConditions1())
.count();
//Number of cases when condition 2 is applied to the input
inputs.stream()
.filter(i -> i.isConditions2())
.count();
//Condition 3 for input,Number of cases when 4 is applied
inputs.stream()
.filter(i -> i.isConditions3())
.filter(i -> i.isConditions4())
.count();
//Condition 1 for input, 3,Number of cases when 5 is applied
inputs.stream()
.filter(i -> i.isConditions1())
.filter(i -> i.isConditions3())
.filter(i -> i.isConditions5())
.count();
}
So,
/**
*Output with aggregated results.
*/
@Data
class OutputDto {
/**Number of cases to which condition 1 was applied*/
private Long count1;
/**Number of cases to which condition 2 is applied*/
private Long count2;
/**Condition 3,Number of cases to which 4 was applied*/
private Long count3And4;
/**Condition 1, 3,Number of cases to which 5 was applied*/
private Long count1And3And5;
// ...
}
When filling the output DTO like this,
private void makeOutput(List<InputDto> inputs) {
OutputDto.builder()
.count1(inputs.stream()
.filter(i -> i.isConditions1())
.count())
.count2(inputs.stream()
.filter(i -> i.isConditions2())
.count())
.count3And4(inputs.stream()
.filter(i -> i.isConditions3())
.filter(i -> i.isConditions4())
.count())
.count1And3And5(inputs.stream()
.filter(i -> i.isConditions1())
.filter(i -> i.isConditions3())
.filter(i -> i.isConditions5())
.count())
.build();
}
Is it like this?
The condition is boolean
so I can still read it, but I couldn't see it when the child's DTO came out: tired_face:
So I wondered if it would be easier to read.
Java's Stream API
is convenient, but if you write it in a list such as a lambda expression, it may become difficult to read.: Disappointed_relieved:
So, I thought about dividing the methods so that I could understand ** what I wanted to do **.
Long filter and aggregate(List<InputDto>List of inputs, Predicate<? super InputDto>...Lots of filters) {
//Gonyo Gonyo
Number of returns;
}
Like this.
In addition, if you write a lot of filters
in a lambda expression, it will remain difficult to see, so that is also a method.
Predicate<? super InputDto>A certain filter() {
return input->Filtering using inputs;
}
// ...abridgement
This way, when you use it
Filter and aggregate(List of inputs,A certain filter(),Other filters());
It's like ** Easy to read and shorter! I thought **.
The filter and aggregate
method
/**
*Applies all filters passed as variadic to the list of inputs and returns the number.
*
* @param inputs
* @param filters
* @Number of cases after applying the return filter
*/
private final Long filterCount(List<InputDto> inputs, Predicate<? super InputDto>... filters) {
Stream<InputDto> work = inputs.stream();
for (Predicate<? super InputDto> filter : filters) {
work = work.filter(filter);
}
return work.count();
}
I implemented it like this.
Since Stream
cannot be reused, it feels like filtering with a for-each statement
.
The certain filter
method
/**
* @return {@link InputDto#isConditions1()}Filter using
*/
private Predicate<? super InputDto> filter1() {
return i -> i.isConditions1();
}
/**
* @return {@link InputDto#isConditions2()}Filter using
*/
private Predicate<? super InputDto> filter2() {
return i -> i.isConditions2();
}
// ...Omission
/**
* @return {@link InputDto#isConditions5()}Filter using
*/
private Predicate<? super InputDto> filter5() {
return i -> i.isConditions5();
}
We have prepared it at the minimum level so that it can be reused.
If you rewrite the process of packing in the output that appeared in the introduction
private void makeOutput(List<InputDto> inputs) {
OutputDto.builder()
.count1(filterCount(inputs, filter1()))
.count2(filterCount(inputs, filter2()))
.count3And4(filterCount(inputs, filter3(), filter4()))
.count1And3And5(filterCount(inputs, filter1(), filter3(), filter5()))
.build();
}
I feel like this.
How is it? Easy to read: thinking :: question:
This was the code I wrote a long time ago, but I remembered that other people said it was useful.
I was happy because I wrote it with a lot of trouble, but ** Is there a better way to write it? The question came up and I wrote the article.
Java programmers out there!
Regardless of the Stream API
I would be grateful if you could let me know! : yum:
** I got a code example that fits nicely in the comment section! Please see if you are interested! !! ** **
--Although not mentioned in the article, the code uses lombok
.
-** You can read it even if you use a method! There may be an opinion like **, but the data actually handled has a complicated hierarchical structure, and there are about 20 types of aggregation patterns. I hope you can imagine it and read it.
Recommended Posts