본문 바로가기
[ JAVA ]/JAVA

[ Java ] java.util.stream.IntStream 주요 메서드 정리

by 환이s 2024. 5. 23.
728x90


오늘은 토이 프로젝트 생성하면서 테이블 생성 테스트 코드 작성할 때

활용했던 java.util.stream.IntStream에 대해 포스팅해 보겠습니다😄

 

주요 메서드 정리 및 개념에 대해 다루고

실전 예제 코드를 통해서 각 메서드에 장단점을 알아보는 시간을 가지겠습니다


IntStream - 소개

 

IntStream은 Java 8에서 도입된 Stream API의 일부분으로,

'int' 기본형에 특화된 스트림입니다.

 

Stream API는 Java에서 함수형 프로그래밍 스타일을 사용하여 데이터 처리를 할 수 있도록 도와주고

IntStream'Stream<Integer>' 와는 다르게 오토박싱/언박싱의 오버헤드가 없기 때문에 성능적으로 유리합니다.

 

IntStream은 여러 가지 방법으로 다음과 같이 생성해서 사용할 수 있습니다.

 

IntStream.of(int... values)

IntStream.range(int startInclusive, int endExclusive)

IntStream.generate(IntSupplier)

IntStream.iterate(int seed, IntUnaryOperator f)

 

사용법을 확인해 보면

코드를 간결하게 사용할 수 있고, 간결함은 즉 가독성도 향상할 수 있습니다.

또한 앞서 언급했듯 'Stream<Integer>' 와는 다르게 오토박싱/언박싱이 필요 없기 때문에 성능을 향상할 수 있고

람다 표현식과 함께 사용하여 함수형 프로그래밍을 구현할 수 있습니다.

 

(람다식은 JDK 1.8(Java 8 버전) 이후에 추가된 객체지향언어입니다. 알아보시는 분들은 아래 블로그 참고해 보시면 좋을 거 같습니다.)

 

[ Java ] Lambda

CHAPTER 25. Lambda Expression 알아가기 오늘은 JDK1.8부터 추가된 람다식(Lambda expression)에 대해서 포스팅해보려 합니다. ■ Lambda expression 람다식(Lambda expression)이란 함수형 프로그래밍의 표현법 입니다.

drg2524.tistory.com

 

물론 장점이 있다면 단점도 있습니다.

스트림은 한 번만 사용할 수 있어서 다시 사용하려면 새로 생성해야 하는 1회성이고,

성능에 민감한 낮은 수준의 제어가 필요한 경우 부적합할 수 있습니다.

 

또한, 스트림 파이프라인이 복잡해지면 디버깅이 어려울 수 있다는 단점이 있는데,

그렇다면 어떤 상황에 사용해야 적합하고 사용하면 안 되는 상황을 나열해 보겠습니다.

 

 

사용에 적합한 상황

 

  • 대량의 데이터를 변환하거나 필터링하는 상황
  • 합계, 평균, 최솟값, 최댓값 등 집계 작업이 필요한 상황
  • 간결하고 가독성 좋은 코드가 필요한 상황
  • 데이터 병렬 처리로 성능 향상이 필요한 상황

 


사용하면 안 되는 상황

 

  • 복잡한 상태 변환이 필요할 때는 부적합합니다.
    • 스트림은 무상태(stateless)를 권장합니다.
  • 성능에 민감하고 낮은 수준의 제어가 필요할 때 부적합합니다.
    • 예를 들어 루프를 정교하게 제어해야 하는 경우에는 부적합합니다.
  • 디버깅이 중요한 코드에는 부적합합니다.
    • 스트림 파이프라인이 복잡하면 디버깅이 어려울 수 있습니다.

IntStream - 사용법 및 예제

 

IntStream을 사용법으로 기본적으로 사용하는 예제와 평균 계산, 병렬 스트림 사용할 때 사용법으로 다뤄보겠습니다.

 

먼저 기본적으로 사용하는 예제입니다.

 

기본적인 사용 예제

IntStream을 생성하고 1~10까지의 수 중에 짝수 값을 출력하는 코드입니다.

import java.util.stream.IntStream;

public class TestIntStream {
    public static void main(String[] args) {
        // IntStream 생성 및 기본 연산
        IntStream.range(1, 10)
                 .filter(n -> n % 2 == 0)
                 .forEach(System.out::println);
    }
}

 

위 코드를 분석해 보면 range(1,10)에 1부터 9까지의 값을 생성하고 해당 필터를 통해서 짝수만 필터링합니다.

출력해 보면 다음과 같은 결과를 확인할 수 있습니다.

2
4
6
8

 

평균 계산 예제

평균 계산 예제로는 1부터 99가지의 값을 생성해서 짝수 값들의 평균을 계산하는 코드입니다.

 

import java.util.OptionalDouble;
import java.util.stream.IntStream;

public class TestIntStream {
    public static void main(String[] args) {
        // IntStream을 사용하여 평균 계산
        OptionalDouble average = IntStream.range(1, 100)
                                          .filter(n -> n % 2 == 0)
                                          .average();

        average.ifPresent(System.out::println);
    }
}

 

average()는 필터링된 값들의 평균을 계산할 때 사용합니다.

 

ifPresent()은 평균이 존재하면 출력할 수 있게 선언하였고 실행해 보면 다음과 같은 평균값을 확인할 수 있습니다.

50.0

 

병렬 스트림 예제 

import java.util.stream.IntStream;

public class TestIntStream {
    public static void main(String[] args) {
        // 병렬 스트림을 사용하여 합계 계산
        int sum = IntStream.range(1, 1000000)
                           .parallel()
                           .sum();

        System.out.println("Sum: " + sum);
    }
}

 

병렬 스트림 예제에서는 1부터 999999까지의 값을 생성하고

'parallel()'을 선언하여 스트림을 병렬 처리와 sum() 메서드를 사용해서 모든 값을 더합니다.

 

출력 결과는 다음과 같습니다.

Sum: 499999500000

 

지금까지 각 예제를 통해서 IntStream의 사용법에 대해 알아봤습니다.

마지막으로 주요 메서드를 예제를 통해서 알아보고 마무리하겠습니다.


IntStream - 주요 메서드 소개 및 예제

 

주요 메서드를 예제를 통해서 알아볼 텐데,

별도의 설명은 코드에 간단하게 주석 처리하겠습니다.

 

Map

import java.util.stream.IntStream;

public class TestIntStream {
    public static void main(String[] args) {
        // IntStream을 사용하여 값을 제곱
        // map => 각 요소에 함수(여기서는 제곱)를 적용하여 새로운 스트림을 반환
        IntStream.range(1, 5)
                 .map(n -> n * n)
                 .forEach(System.out::println);
    }
}

 

// 출력 결과
1
4
9
16

reduce

import java.util.stream.IntStream;

public class IntStreamExample {
    public static void main(String[] args) {
        // IntStream을 사용하여 값의 합을 계산
        // reduce => 초기값(0)과 누적기 함수((a,b) -> a+b)를 사용하여 스트림의 모든 요소를 결합
        int sum = IntStream.range(1, 5)
                           .reduce(0, (a, b) -> a + b);

        System.out.println("Sum: " + sum);
    }
}
//출력 결과
Sum: 10

sum

import java.util.stream.IntStream;

public class IntStreamExample {
    public static void main(String[] args) {
        // IntStream을 사용하여 값의 합을 계산
        // sum => 모든 요소를 더한다
        int sum = IntStream.range(1, 5).sum();

        System.out.println("Sum: " + sum);
    }
}
//출력 결과
Sum: 10

max

import java.util.OptionalInt;
import java.util.stream.IntStream;

public class IntStreamExample {
    public static void main(String[] args) {
        // IntStream을 사용하여 최대값을 찾기
        // max => 최대값을 반환
        OptionalInt max = IntStream.range(1, 5).max();

        max.ifPresent(value -> System.out.println("Max: " + value));
    }
}
//출력 결과
Max: 4

min

import java.util.OptionalInt;
import java.util.stream.IntStream;

public class IntStreamExample {
    public static void main(String[] args) {
        // IntStream을 사용하여 최소값을 찾기
        // min => 최소값을 반환
        OptionalInt min = IntStream.range(1, 5).min();

        min.ifPresent(value -> System.out.println("Min: " + value));
    }
}
//출력 결과
Min: 1

average

import java.util.OptionalDouble;
import java.util.stream.IntStream;

public class IntStreamExample {
    public static void main(String[] args) {
        // IntStream을 사용하여 평균을 계산
        // average => 스트림의 평균값을 반환
        OptionalDouble avg = IntStream.range(1, 5).average();

        avg.ifPresent(value -> System.out.println("Average: " + value));
    }
}
//출력 결과
Average: 2.5

distinct

import java.util.stream.IntStream;

public class TestIntStream {
    public static void main(String[] args) {
        // IntStream을 사용하여 중복 제거
        // distinct => 중복된 요소를 제거하고 새로운 스트림을 반환
        IntStream.of(1, 2, 2, 3, 4, 4, 5)
                 .distinct()
                 .forEach(System.out::println);
    }
}
//출력 결과
1
2
3
4
5

sorted

import java.util.stream.IntStream;

public class TestIntStream {
    public static void main(String[] args) {
        // IntStream을 사용하여 정렬
        // sorted => 스트림의 요소를 정렬
        IntStream.of(5, 3, 1, 4, 2)
                 .sorted()
                 .forEach(System.out::println);
    }
}
//출력 결과
1
2
3
4
5

boxed

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

public class TestIntStream {
    public static void main(String[] args) {
        // IntStream을 사용하여 Integer 객체 리스트로 변환
        List<Integer> integerList = IntStream.range(1, 5)
                                             .boxed()
                                             .collect(Collectors.toList());

        System.out.println(integerList);
    }
}
//출력 결과
[1, 2, 3, 4]

마치며

 

'IntStream'을 통해 성능을 개선하고, 간결한 코드를 작성할 수 있지만

모든 상황에 적합하지 않으므로 적절한 상황에서 사용하는 것이 중요한 거 같습니다

 

특히, 성능에 민감한 낮은 수준의 제어나 복잡한 상태 변환이 필요할 때는 다른 방법을 고려해 봐야겠습니다😅

 

728x90