int[] intArray = {1, 2, 3, 4, 5};
Arrays.stream(intArray)
.forEach(i -> System.out.println(i));
배열 내 인자들 출력
1
2
3
4
5
int[] intArray = {1, 2, 3, 4, 5};
Stream.of(intArray)
.forEach(i -> System.out.println(i));
int[] 배열 자체 반환
[I@7dc36524
결과만 먼저 정리하자면, 결과가 동일합니다.
Integer[] IntegerArray = {1, 2, 3, 4, 5};
Arrays.stream(IntegerArray)
.forEach(i -> System.out.println(i));
[결과]
1
2
3
4
5
Integer[] IntegerArray = {1, 2, 3, 4, 5};
Stream.of(IntegerArray)
.forEach(i -> System.out.println(i));
1
2
3
4
5
위에서 봤듯이 primitive 배열에서만 결과가 달랐는데, 왜 차이가 나는지 살펴보겠습니다. Stream.of() 로 만들었을 때는 배열 자체를 단일 요소로 취급하고 [I@7dc36524 이런식으로 반환한 걸 볼 수 있었는데요.


이에 대한 이유는 생성하는 부분의 메서드를 보면 알 수 있습니다.
여기서는 int primitive 타입에 특화된 IntStream을 반환합니다. 따라서 Integer로 boxing 되지 않고 int 타입 그대로 사용할 수 있습니다.
/**
* Returns a sequential {@link IntStream} with the specified array as its
* source.
*
* @param array the array, assumed to be unmodified during use
* @return an {@code IntStream} for the array
* @since 1.8
*/
public static IntStream stream(int[] array) {
return stream(array, 0, array.length);
}
Stream.of 는 가변인자 메서드로, 제네릭 타입 T를 가변인자로 받습니다. 그리고 컴파일 시점에 배열로 변환이 되고 그 배열로 Arrays.stream() 을 호출하게 됩니다.
/**
* Returns a sequential ordered stream whose elements are the specified values.
*
* @param <T> the type of stream elements
* @param values the elements of the new stream
* @return the new stream
*/
@SafeVarargs
@SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) {
return Arrays.stream(values);
}
이 때 primitive type 은 제네릭 타입 인자로 쓸 수 없습니다. 따라서 컴파일러는 int[] 이 배열 자체를 인자로 선택할 수 밖에 없게 됩니다.
String[] 이나 Integer[] 와 같은 referece type 배열은 제네릭 타입 인자로 해석될 수 있기 때문에, 위에서 봤던 것처럼 잘 풀려서 하나씩 출력이 되는 것을 볼 수 있었습니다.
이미 int[] 배열이 있다면, Arrays.stream() 을 사용하는 게 좋지만, Stream.of()는 아래와 같이 배열을 정의하지 않고 바로 스트림을 만들어서 활용할 수 있습니다.
Stream.of(1, 2, 3, 4, 5)
.forEach(i -> System.out.println(i));
컴파일러는 이 숫자들을 Integer.valueof() 를 통해 Integer로 boxing 하기 때문에, 제너릭 타입으로 해석이 가능해집니다. 다만, 이렇게 할 경우, 아래와 같은 단계들이 수행되기 때문에, 대부분의 경우 배열을 스트림으로 만드려면 Arrays.stream()이 권장된다고 합니다.
- int -> Integer 로 오토 박싱
- 가변인자들을 배열로 변환
- 스트림 생성
Stream.of() 또는 Stream.ofNullable()은 스트림을 생성할 때 사용하는 것보다 아래와 같이 스트림을 합치거나 null 처리를 하는 중간 연산으로서 의미가 있다고 볼 수 있습니다.
Stream.concat(
mainStream,
Stream.of(extraValue)
)
저는 스트림을 잘 모르다보니 이렇게 스트림 생성조차 헷갈렸는데, 비슷한 의문을 가지고 있는 분들께 도움이 되셨길 바라며 마치겠습니다.