I tried to create a method to apply multiple filters at once with Java Stream API. Is this okay?

Before

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.

I thought about a method that I thought was easy to read

Thoughts

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 **.

What I implemented

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.

I actually used it

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:

Was this all right?

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

There is such a way of writing-it's easy to read-

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! !! ** **

Notice

--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

I tried to create a method to apply multiple filters at once with Java Stream API. Is this okay?
I tried to create a java8 development environment with Chocolatey
I tried to break a block with java (1)
I tried to create a shopping site administrator function / screen with Java and Spring
[Azure] I tried to create a Java application for free ~ Connect with FTP ~ [Beginner]
I tried to modernize a Java EE application with OpenShift.
[Rails] I tried to create a mini app with FullCalendar
I tried to create a padrino development environment with Docker
I want to write a loop that references an index with Java 8's Stream API
Since the reading of JdbcCodeList of TERASOLUNA is slow, I tried to register multiple at once.
I tried to interact with Java
I tried using Java8 Stream API
[Java] I tried to make a maze by the digging method ♪
I tried to create an API to get data from a spreadsheet in Ruby (with service account)
I tried to make a Web API that connects to DB with Quarkus
I want to create a dark web SNS with Jakarta EE 8 with Java 11
I tried to summarize the Stream API
I tried to solve 10 selected past questions that should be solved after registering with AtCoder with Java, Stream API
When I wanted to create a method for Premium Friday, it was already in the Java 8 standard API
I tried to make a program that searches for the target class from the process that is overloaded with Java
[Java] I installed JDBC and tried to connect with servlet + MySQL. (There is a version using DAO / Bean)
I tried to create a portfolio with AWS, Docker, CircleCI, Laravel [with reference link]
[Java] I tried to connect using a connection pool with Servlet (tomcat) & MySQL & Java
[Azure] I tried to create a Java application for free-Web App creation- [Beginner]
I tried to make Basic authentication with Java
java I tried to break a simple block
I tried to create a LINE clone app
I tried to create Alexa skill in Java
I tried to make a product price comparison tool of Amazon around the world with Java, Amazon Product Advertising API, Currency API (2017/01/29)
I tried to create a log reproduction script at the time of apt install
I tried what I wanted to try with Stream softly.
I tried to implement TCP / IP + BIO with JAVA
[Java 11] I tried to execute Java without compiling with javac
I tried to make a login function in Java
I tried to draw animation with Blazor + canvas API
I tried OCR processing a PDF file with Java
I tried to implement Stalin sort with Java Collector
[Java] I tried to implement Yahoo API product search
I want to make a list with kotlin and java!
I want to make a function with kotlin and java!
Create a SlackBot with AWS lambda & API Gateway in Java
Create a method to return the tax rate in Java
I tried to link chat with Minecraft server with Discord API
Even in Java, I want to output true with a == 1 && a == 2 && a == 3
I tried to convert a string to a LocalDate type in Java
Now is the time to get started with the Stream API
I tried to make a client of RESAS-API in Java
I tried OCR processing a PDF file with Java part2
Convert 2D array to csv format with Java 8 Stream API
I tried to be able to pass multiple objects with Ractor
I implemented the code to learn multiple images at once in the Watson Visual Recognition Collection in Java.
I tried to take a look at the flow of Android development environment construction with Android Studio
Create a java method [Memo] [java11]
[Java] Introduction to Stream API
How to create a method
I tried to create a simple map app in Android Studio
I can't create a Java class with a specific name in IntelliJ
I tried to create a Spring MVC development environment on Mac
Connecting to a database with Java (Part 1) Maybe the basic method
I tried to understand how the rails method "redirect_to" is defined
I made a method to ask for Premium Friday (Java 8 version)