[JAVA] Stream API
Stream
- Stream 이란 ? Collection Builder , 람다를 활용할 수 있는 기술 중 하나이다. 이전에는 for문과 foreach문을 돌 때 로직이 복잡해지면서 복잡한 경우가 발생한다. 스트림은 즉, 데이터의 흐름이기 때문에 배열 또는 컬렉션에 함수를 사용하여 원하는 결과를 필터링 할 수 있다는 장점이 있다. 즉 함수형으로 처리할 수 있다.
- Functional Program에는 null을 직접적으로 다루지 않는다.
Functional Program 이 더 안전하고 원하는 것을 더욱 더 쉽게 다룰 수 있다.
(1) InStream
- java.util.stream 패키지 내에 스트림관련 API존재
1
2
3
|
IntStream.range(1,10).forEach(i -> System.out.println(i + "")); // 1 2 3 4 5 6 7 8 9
IntStream.rangeClosed(1,10).forEach(i-> System.out.println(i + " ")); // 1 2 3 4 5 6 7 8 9 10
IntStream.iterate(1, i-> i+1).forEach(i -> System.out.println(i + " ")); // 숫자 계속 증가
|
cs |
(2) Stream
1
2
|
Stream.iterate(BigInteger.ONE, i-> i.add(BigInteger.ONE))
.forEach(i -> System.out.println(i + " ")); // 무한대의 Integer
|
cs |
- 메모리가 허락하는한 무한대의 Integer을 가짐
- Functional Programming 처럼 무한대의 Integer가짐
1
2
|
Stream.of(1,2,3,4,5,6)
.forEach(i -> System.out.println( i + " ")); // 1 2 3 4 5 6
|
cs |
* Imperative Programming과 Functional Programming 차이
- Stream Builder는 굉장히 게으른 Collection Builder.
- 아무 일도 안함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
final List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
//final List<Integer> result = new ArrayList<>();
Integer result = null;
for(final Integer number : numbers){
if(number > 3 && number < 9){
final Integer newNumber = number * 2 ;
if(newNumber > 10 ){
result = newNumber;
break;
}
}
}
System.out.println("Imperative Result : " + result); // 12
System.out.println("Functional Result : " +
numbers.stream()
.filter(number -> number > 3 )
.filter(number -> number < 9 )
.map(number -> number *2 )
.filter(number -> number > 10)
.findFirst()
); //12
|
cs |
다른식으로도 표현할 수 있지만 가장 좋은 표현방식은 위와 같은 표현방식이다.
하단과 같이 표현하는 것은 불필요한 표현방식이다.
1
2
3
4
5
6
|
final List<Integer> greaterThan3 = filter(numbers, i -> i>3);
final List<Integer> lessThan9 = filter(greaterThan3, i -> i<9);
final List<Integer> doubled = map(lessThan9, i -> i*2);
final List<Integer> greaterThan10 = filter(doubled, i -> i>10);
System.out.println(greaterThan10.get(0));
|
cs |
다음은 가독성이 좋지 않다.
1
2
|
final List<Integer> myOwnMethodResult = filter(map(filter(filter(numbers, i-> i>3), i-> i<9), i-> i*2 ), i-> i>10);
System.out.println(myOwnMethodResult);
|
cs |
<filter, map Generic>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
private static <T> List<T> filter(List<T> list, Predicate<? super T> predicate){
final List<T> result = new ArrayList<>();
for(final T t : list){
if(predicate.test(t)){
result.add(t);
}
}
return result;
}
private static <T,R> List<R> map(List<T> list, Function<T,R> mapper){
final List<R> result = new ArrayList<>();
for(final T t : list){
result.add(mapper.apply(t));
}
return result;
}
|
cs |
<시작하기전에 - 참고 >
1
2
3
4
5
|
final int minInt = Math.abs(Integer.MIN_VALUE);
final int maxInt = Math.abs(Integer.MAX_VALUE);
System.out.println("maxInt " + maxInt); // 2147483647
System.out.println("minInt " + minInt); // -2147483648
|
cs |
<1> Indentity Function
- 같은 타입을 리턴하는 것 , 함수 하는일은? 입력값을 받아서 그대로 리턴하는 것을 의미함
- 타입 매개 변수 종류 --> E - Element / K - Key / N - Number / T - Type / V - Value
1
2
3
4
5
6
7
8
9
10
11
12
|
...
final List<Integer> numbers = Arrays.asList(1,2,3,4,5);
System.out.println(map(numbers, i-> i*2)); // [2, 4, 6, 8, 10]
}
private static <T,R> List<R> map(List<T> list, Function<T,R> mapper){
final List<R> result = new ArrayList<>();
for(final T t : list){
result.add(mapper.apply(t));
}
return result;
}
|
cs |
..
System.out.println(map(numbers, i-> i)); //1,2,3,4,5
System.out.println(map(numbers, Function.identity())); //1,2,3,4,5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
private static <T, R> List<R> map(final List<T> list, final Function<T,R> mapper){
final Function<T,R> function;
if(mapper != null){
function = mapper;
}else{
function = t-> (R) t;
}
final List<R> result = new ArrayList<>();
for(final T t : list){
result.add(function.apply(t));
}
return result;
}
|
cs |
Lazy
- Intermediate Operation Method
- Terminal Operation Method
<출처>
2. 유투브 kevin TV - 모던자바