본문 바로가기
쿤즈 Dev/Java

[Java] stream() 메소드를 이용해서 Collection 객체 가공하는 방법

by Koonz:) 2021. 8. 18.
728x90

Java를 사용해서 애플리케이션을 만들고, 또 웹을 만들다 보면 Java8 버전의 stream() 메서드를 많이 사용하게 됩니다. 여러 번의 반복된 작업을 굉장히 간략히 변경해서 사용하고, 또 객체들을 가공할 수 있기 때문이죠.

이번 포스팅에서는 Java8에서 등장한 stream() 메소드를 사용해서 Collection 객체들을 가공하는 방법에 대해서 알아보도록 하겠습니다.


Collection 객체를 이용해서 데이터 가공

Collection 객체들 중 가장 많이 사용하는 객체는 List라 생각됩니다. 여러 가지 동일한 형태의 자료들을 모아서 관리할 수 있기 때문이죠. 우선 간단하게 프로젝트를 하나 만들어서 확인해 보도록 하겠습니다.

 

package name : com.koonsland.stream

class name : Main

package stream;

import java.util.ArrayList;
import java.util.List;

import static stream.Main.Gender.*;

public class Main {
    public static void main(String[] args) {
        // List.of() 메소드는 Java9 버전에서 사용하는 메소드입니다.
        // 1. Student를 가지는 List 생성
        List<Student> studentList = List.of(
                new Student("Ironman", 15, MALE),
                new Student("Hulk", 18, MALE),
                new Student("Captain", 17, MALE),
                new Student("Black widow", 14, FEMALE)
        );

        // 2. studentList에서 성별이 MALE인 학생만 males에 저장 
        List<Student> males = new ArrayList<>();
        for (Student student : studentList) {
            if(MALE.equals(student.gender)) {
                males.add(student);
            }
        }

        // 3. 정상적으로 저장되었는지 확인
        for (Student male : males) {
            System.out.println(male);
        }
    }

    static class Student {
        private final String name;
        private final int age;
        private final Gender gender;

        public Student(String name, int age, Gender gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    '}';
        }
    }

    enum Gender {
        MALE, FEMALE
    }
}

소스 설명을 드리도록 하겠습니다.

우선 Student라는 클래스를 하나 만들어 줍니다. 이 클래스는 name(이름), age(나이), genter(성별)을 멤버 변수로 가지는 클래스입니다. 그리고 gender는 enum을 사용하여 MALE, FEMALE 두 가지를 가질 수 있도록 정의했습니다.

 

추가적으로 값을 확인하기 위해서 toString() 메소드를 오버라이드(@Override) 했어요.

 

가장 먼저 새로운 학생들을 List로 만들어 주도록 합니다.

// List.of() 메소드는 Java9 버전에서 사용하는 메소드입니다.
// 1. Student를 가지는 List 생성
List<Student> studentList = List.of(
  new Student("Ironman", 15, MALE),
  new Student("Hulk", 18, MALE),
  new Student("Captain", 17, MALE),
  new Student("Black widow", 14, FEMALE)
);

매번 new를 이용해서 생성하고 add() 메소드를 이용해서 넣어도 되지만 List.of()라는 메서드를 통해서 동일 작업을 간단하게 줄여서 작업했습니다.

studentList 변수는 Student 객체를 담을 수 있는 List입니다. 그리고 이 리스트에는 총 4명의 학생이 저장되어 있습니다.

 

다음인 이 학생들 중에서 남학생만을 추출해 보도록 하겠습니다.

// 2. studentList에서 성별이 MALE인 학생만 males에 저장
List<Student> males = new ArrayList<>();
  for (Student student : studentList) {
    if(MALE.equals(student.gender)) {
    	males.add(student);
  }
}

데이터를 추출하는 방법은 for문을 사용해서 studentList에 있는 객체를 하나씩 가져옵니다. 이때 가져온 학생의 성별이 남학생이면 새롭게 생성한 리스트인 males 변수에 추가하도록 합니다.

 

다음은 정상적으로 데이터를 가져왔는지 확인하기 위한 소스코드입니다.

// 3. 정상적으로 저장되었는지 확인
for (Student male : males) {
  System.out.println(male);
}

리스트변수인 males에서 Student 객체를 하나씩 가져와서 화면에 출력합니다.

Student{name='Ironman', age=15, gender=MALE}
Student{name='Hulk', age=18, gender=MALE}
Student{name='Captain', age=17, gender=MALE}

위와 같이 나오기 위해서는 Student 클래스에서 toString() 메서드를 오버라이드 했기 때문입니다.

그럼 이제 위 작업들을 java8의 함수형인 stream() 메소드를 이용해서 간단하게 바꿔보도록 하겠습니다.


Java stream() 메소드 사용해서 데이터 가공

우선 기존 데이터 저장하는 1번은 그대로 두고 2번을 변경해 보도록 하겠습니다. 전체 소스는 이렇습니다.

package stream;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static stream.Main.Gender.*;

public class Main {
    public static void main(String[] args) {
        // List.of() 메소드는 Java9 버전에서 사용하는 메소드입니다.
        // 1. Student를 가지는 List 생성
        List<Student> studentList = List.of(
                new Student("Ironman", 15, MALE),
                new Student("Hulk", 18, MALE),
                new Student("Captain", 17, MALE),
                new Student("Black widow", 14, FEMALE)
        );

        // 2. studentList에서 성별이 MALE인 학생만 males에 저장
        /*List<Student> males = new ArrayList<>();
        for (Student student : studentList) {
            if(MALE.equals(student.gender)) {
                males.add(student);
            }
        }*/
        
        // 2.1. studentList에서 stream()메소드를 이용해서 MALE인 학생만 males에 저장
        List<Student> males = studentList.stream()
                .filter(student -> MALE.equals(student.gender))
                .collect(Collectors.toList());

        // 3. 정상적으로 저장되었는지 확인
        for (Student male : males) {
            System.out.println(male);
        }
    }

    private static class Student {
        private final String name;
        private final int age;
        private final Gender gender;

        public Student(String name, int age, Gender gender) {
            this.name = name;
            this.age = age;
            this.gender = gender;
        }

        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", gender=" + gender +
                    '}';
        }
    }

    enum Gender {
        MALE, FEMALE
    }
}

위 소스에서 중점적으로 봐야할 부분은 2.1번입니다. studentList 변수에서 stream() 메서드를 사용했습니다. 이 메서드는 Collection이 가지고 있는 객체를 소스로 하는 Stream 클래스로 반환합니다.

Stream<Student> streamStudent = studentList.stream();

이 Stream 객체는 아래와같이 여러 가지 함수들을 가지고 있습니다.

전체 값을 가공 시에는 map() 메서드를, 특정 값을 필터링하고 싶을 때에는 filter() 메서드를 사용할 수 있습니다. 기능들은 추후 하나씩 다뤄보도록 할게요.

// 2.1. studentList에서 stream()메소드를 이용해서 MALE인 학생만 males에 저장
List<Student> males = studentList.stream()
  .filter(student -> MALE.equals(student.gender))
  .collect(Collectors.toList());

우선 위 소스에서는 filter 기능을 사용했습니다. 이 경우에는 javascript 처럼 ->(Predicate)라는 타입을 사용합니다. filter에서 첫 student는 리스트 중 하나의 값이 전달됩니다. 이 값이 student라는 변수로 사용되고 이 변수와 MALE을 비교합니다.

 

하나씩 비교해서 그 결과가 true이면 Stream 타입의 리스트로 가지고 있습니다. 그리고 이를 다시 collect() 메소드를 이용해서 list의 형태로 변경해줍니다.

 

처음에는 굉장히 복잡하고 어려워보이지만 사용방법이 익숙해진다면 굉장히 자주, 그리고 많이 사용하게 될 문법입니다. 특히 Spring boot를 이용해서 데이터를 가공처리하는 과정에서 많이 사용될 수 있습니다.


이번 포스팅에서는 stream() 메소드와 filter() 메서드를 이용해서 List형태인 Collection 데이터를 가공해 보았습니다. Java8 이하 버전을 사용한다면 이 구분을 볼 수 없겠지만 Spring boot 프레임워크를 이용한 웹 개발을 하신다면 자주 사용할 수 있는 구문입니다. 도움이 되셨으면 합니다. 이상입니다.

댓글