본문 바로가기

SearchDeveloper/Java

[JAVA] stream 코드 스니펫

JAVA 8 부터 도입된 stream. 내가 사용했을 때 느꼈던 가장 큰 장점은 데이터가 어떻게 흘러가는지가 문장읽듯이 읽혀서 코드 가독성이 좋다는 점이다. 처음에는 사용법을 잘 몰라 어려웠지만 하나씩 하나씩 작성해보니 꽤나 익숙해졌고 코드 짤 때도 stream의 비중이 높아지고 있다. 다음은 내가 작성했던 stream 관련 코드 예제이다.

 

배열 출력하기

/* 배열 출력 */
String[] alphabetArr = new String[]{"A", "B", "C"};
Arrays.stream(alphabetArr).forEach(alphabet -> log.info(alphabet));

 

stream 함수 안에서 여러 문장 실행하기

List<Person> personList = new ArrayList<>();

/* 멀티 라인 */
personList.stream().forEach(person -> {
    person.setName("아무개");
    person.setAge(13);
});

forEach() 등 stream 메소드 안에서 여러 라인을 실행하고 싶을 때 {} 로 묶을 수 있다.

 

anyMatch, allMatch, noneMatch

/* personList 중 한 요소라도 조건을 만족하면 true 반환 */
boolean anyMatch = personList.stream()
        .anyMatch(person -> (person.getAge() == 13) && ("아무개".equals(person.getName())));

/* personList 중 모든 요소가 조건을 만족하면 true 반환 */
boolean allMatch = personList.stream()
        .allMatch(person -> (person.getAge() == 13) && ("아무개".equals(person.getName())));

/* personList 중 모든 요소가 조건을 만족하지 않으면 true 반환 */
boolean noneMatch = personList.stream()
        .noneMatch(person -> (person.getAge() == 13) && ("아무개".equals(person.getName())));

anyMatch 한 요소라도 조건을 만족하면 true

allMatch 모든 요소가 조건을 만족하면 true

noneMatch 모든 요소가 조건을 만족하지 않으면 true

 

filter, findFirst

/* personList에서 filet 조건을 첫 번째로 만족하는 요소 반환 */
Person firstPerson = personList.stream()
	                .filter(person -> "아무개".equals(person.getName()))
	                .findFirst()
	                .get();

filter 해당 조건 만족하는 요소만 다음 stream 으로 넘긴다.

findFirst 첫 번째로 조건 만족하는 요소 찾기

 

collect

/* personList에서 age만 모아 List 로 반환 */
List<Integer> ageList = personList.stream()
        .map(person -> person.getAge())
        .collect(Collectors.toList());

/* personList에서 age만 모아 Set 으로 반환 */
Set<Integer> ageSet = personList.stream()
        .map(person -> person.getAge())
        .collect(Collectors.toSet());

.map(person -> person.getAge()) age 값들을 다음 stream으로 넘긴다.

.collect(Collectors.toList()) 받은 age 값들은 List로 반환

.collect(Collectors.toSet()) 받은 age 값들은 Set으로 반환

 

Map 다루기

/* personList에서 key가 name이고 value가 age인 Map 만들기 */
Map<String, Integer> personMap = personList.stream()
        .collect(Collectors.toMap(Person::getName, Person::getAge));

/* personMap에서 value가 13인 요소의 key 리스트 반환 */
List<String> age13NameList = personMap.entrySet().stream()
        .filter(person -> person.getValue() == 13)
        .map(person -> person.getKey())
        .collect(Collectors.toList());

/* personMap에서 value가 13인 요소의 key를 "," 로 이어붙이기 */
String names = personMap.entrySet().stream()
        .filter(person -> person.getValue() == 13)
        .map(Map.Entry::getKey)
        .collect(Collectors.joining(","));

.collect(Collectors.toMap(Person::getName, Person::getAge)) 받은 Person의 name, age 값들을 Map으로 반환

.collect(Collectors.joining(",")) 넘어온 값들을 "," 로 join한 string 반환

 

mapToInt, mapToDouble, mapToObj + max, average + IntStream

/* personMap의 key인 name의 최대 글자 수 구하기 */
int nameMaxLength = personMap.keySet().stream()
        .mapToInt(name -> name.length())
        .max()
        .getAsInt();

/* 나이 평균 구하기 */
double ageAvg = ageList.stream()
        .filter(Objects::nonNull)
        .mapToDouble(age -> age)
        .average()
        .getAsDouble();

/* personList에서 짝수 인덱스 요소만 리스트로 반환 */
List<Person> subPersonList = IntStream.range(0, personList.size())
        .filter(i -> i % 2 == 0)
        .mapToObj(personList::get)
        .collect(Collectors.toList());

.mapToInt(name -> name.length()) name.length()를 int형으로 변환해 다음 stream으로 전달

.max() 넘어온 값들 중 최댓값 구하기

 

.mapToDouble(age -> age) age 값을 double로 변환해 next stream으로 전달

.average() 넘어온 값들의 평균 구하기

IntStream.range(0, personList.size()) 0 ~ personList.size() - 1 까지 숫자를 넘김

.mapToObj(personList::get) personList.get(i) 요소를 Object형으로 변환해 다음 stream으로 전달

 

reduce

/* ageList 에서 마지막 요소 값 반환 */
Integer lastAge = ageList.stream()
        .reduce((age1, age2) -> age2)
        .get();

 

디렉토리 안의 파일 경로 접근하기

Path dirPath = Paths.get("/");
/* 디렉토리의 .txt 파일 경로만 가지고 작업 */
Files.walk(dirPath).filter(path -> path.toString().endsWith(".txt")).forEach(path ->
        doFileWork(path)
);

.filter(path -> path.toString().endsWith(".txt")) ".txt"로 끝나는 경로만 doFileWork() 실행

 

전체 코드 참고

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
class StreamTests {

    @Test
    void stream() {
        /* 배열 출력 */
        String[] alphabetArr = new String[]{"A", "B", "C"};
        Arrays.stream(alphabetArr)
                .forEach(alphabet -> log.info(alphabet));
    }

    @Test
    void person() {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person());

        /* 멀티 라인 */
        personList.stream().forEach(person -> {
            person.setName("아무개");
            person.setAge(13);
        });

        /* personList 중 한 요소라도 조건을 만족하면 true 반환 */
        boolean anyMatch = personList.stream()
                .anyMatch(person -> (person.getAge() == 13) && ("아무개".equals(person.getName())));

        /* personList 중 모든 요소가 조건을 만족하면 true 반환 */
        boolean allMatch = personList.stream()
                .allMatch(person -> (person.getAge() == 13) && ("아무개".equals(person.getName())));

        /* personList 중 모든 요소가 조건을 만족하지 않으면 true 반환 */
        boolean noneMatch = personList.stream()
                .noneMatch(person -> (person.getAge() == 13) && ("아무개".equals(person.getName())));

				/* personList에서 filet 조건을 첫 번째로 만족하는 요소 반환 */
        Person firstPerson = personList.stream()
                .filter(person -> "아무개".equals(person.getName()))
                .findFirst()
                .get();

        /* personList에서 age만 모아 List 로 반환 */
        List<Integer> ageList = personList.stream()
                .map(person -> person.getAge())
                .collect(Collectors.toList());

        /* personList에서 age만 모아 Set 으로 반환 */
        Set<Integer> ageSet = personList.stream()
                .map(person -> person.getAge())
                .collect(Collectors.toSet());

        /* personList에서 key가 name이고 value가 age인 Map 만들기 */
        Map<String, Integer> personMap = personList.stream()
                .collect(Collectors.toMap(Person::getName, Person::getAge));

        /* personMap에서 value가 13인 요소의 key 리스트 반환 */
        List<String> age13NameList = personMap.entrySet().stream()
                .filter(person -> person.getValue() == 13)
                .map(person -> person.getKey())
                .collect(Collectors.toList());

        /* personMap에서 value가 13인 요소의 key를 "," 로 이어붙이기 */
        String names = personMap.entrySet().stream()
                .filter(person -> person.getValue() == 13)
                .map(Map.Entry::getKey)
                .collect(Collectors.joining(","));

        /* personMap의 key인 name의 최대 글자 수 구하기 */
        int nameMaxLength = personMap.keySet().stream()
                .mapToInt(name -> name.length())
                .max()
                .getAsInt();

        /* 나이 평균 구하기 */
        double ageAvg = ageList.stream()
                .filter(Objects::nonNull)
                .mapToDouble(age -> age)
                .average()
                .getAsDouble();

        /* personList에서 짝수 인덱스 요소만 리스트로 반환 */
        List<Person> subPersonList = IntStream.range(0, personList.size())
                .filter(i -> i % 2 == 0)
                .mapToObj(personList::get)
                .collect(Collectors.toList());

        /* ageList 에서 마지막 요소 값 반환 */
        Integer lastAge = ageList.stream()
                .reduce((age1, age2) -> age2)
                .get();




    }

    @NoArgsConstructor @AllArgsConstructor @Setter @Getter
    private class Person {
        private String name;
        private Integer age;
    }

    @Test
    public void fileWalking() throws IOException {
        Path dirPath = Paths.get("/");
        /* 디렉토리의 .txt 파일 경로만 가지고 작업 */
        Files.walk(dirPath).filter(path -> path.toString().endsWith(".txt")).forEach(path ->
                doFileWork(path)
        );
    }

    private void doFileWork(Path path) {}

}

 

 

글 읽어주셔서 언제나 감사합니다. 좋은 피드백, 개선 피드백 너무나도 환영합니다.