Java8 스트림과 람다, 그리고 옛날 옛적에는

dropKick·2020년 8월 14일
0

Deep Java See

목록 보기
13/22

개요

  • 문법적 공부는 의미가 없을 것 같고, 이 글을 들어온 사람들에게도 의미가 없을 것
  • 언제 왜 써야하는지 기준으로 비교

자바8 이전의 컬렉션 처리 방식과 비교

List<> 필터링의 경우

for + if

List<String> names = Arrays.asList("John", "Doe", "Jane", "Doe");
List<String> result = new ArrayList<>();

for (String name : names) {
    if (name.startsWith("J")) {
        result.add(name);
    }
}
System.out.println(result); // [John, Jane]

Stream + Lamda

List<String> result = names.stream()
    .filter(name -> name.startsWith("J"))
    .collect(Collectors.toList());
System.out.println(result); // [John, Jane]

✅ 코드의 가독성 향상
✅ 예외 추적이 필요없는 경우

List<> 새로운 매핑값을 만들어내야 하는 경우

for each

List<String> names = Arrays.asList("John", "Jane", "Jack");
List<Integer> nameLengths = new ArrayList<>();

for (String name : names) {
    nameLengths.add(name.length());
}
System.out.println(nameLengths); // [4, 4, 4]

Stream

List<Integer> nameLengths = names.stream()
    .map(String::length)
    .collect(Collectors.toList());
System.out.println(nameLengths); // [4, 4, 4]

✅ 코드 가독성 향상

List<> 내부 요소의 합계를 구해야하는 경우

for

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = 0;

for (int num : numbers) {
    sum += num;
}
System.out.println(sum); // 15

Stream

int sum = numbers.stream()
    .reduce(0, Integer::sum);
System.out.println(sum); // 15

✅ 코드 가독성 향상
✅ 별도 연산 로직 구현보다 제공 함수를 사용

결론

✅ 코드 가독성 향상의 목적
✅ 코드를 선언형 형태로 변경
✅ 스트림 다중 연산 시 병렬 스트림을 통한 성능 최적화
❌ 명확한 예외 처리가 필요한 경우
❌ 람다 표현식 자체가 너무 많아지는 경우
❌ 단순 반복 연산의 경우

단순 반복이 정확히 언제인데요?

단순 반복의 기준

  • 리스트의 단순 조회와 출력
  • 조회의 '수' 자체가 적은 경우
  • 추가 연산이 없는 경우

리스트의 요소 출력

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// for
for (int num : numbers) {
    System.out.println(num);
}

// stream
numbers.forEach(System.out::println);
  • '수'가 적고, 단순 조회인 경우 스트림 내부에서도 for-loop와 동일한 연산을 수행
  • 코드를 선언적으로 바꿔야하는게 아니라면 for문이 더 간결

리스트의 단순 연산

// for
List<Integer> doubled = new ArrayList<>();
for (int num : numbers) {
    doubled.add(num * 2);
}
System.out.println(doubled);

// stream
List<Integer> doubled = numbers.stream()
    .map(num -> num * 2)
    .collect(Collectors.toList());
System.out.println(doubled);
  • 값을 2배로 만들고 다시 삽입하는 단순 반복연산
  • 성능면에서 for-loop는 추가 객체 생성이 없어 유리
  • 코드의 가독성 측면에서 취향 차이

리스트의 대용량 필터링

// 데이터 100만개
List<Integer> numbers = IntStream.range(1, 1_000_000).boxed().collect(Collectors.toList());

// for
List<Integer> filtered = new ArrayList<>();
for (int num : numbers) {
    if (num % 2 == 0) {
        filtered.add(num);
    }
}

// Stream
List<Integer> filtered = numbers.stream()
    .filter(num -> num % 2 == 0)
    .collect(Collectors.toList());

// parallelStream
List<Integer> filtered = numbers.parallelStream()
    .filter(num -> num % 2 == 0)
    .collect(Collectors.toList());
  • 스트림은 자체적으로 병렬 연산을 지원
  • 데이터가 커진다면 스트림은 필수적, 연산에 따라 일반 스트림과 병렬 스트림을 사용
profile
안아줘요

0개의 댓글

관련 채용 정보