.map((파라미터) -> 코드)
각 인덱스의 값을 파라미터로 넘기고 코드를 수행한다
주로 값을 바꿔주거나 더해주거나 할때 사용하게 된다
map은 코드 부분에서 메소드 사용이 불가능한데
이건 아래의 forEach를 사용해주면 된다
전체 예제는 아래에 코드를 넣어놨으니
그걸 봐주면 된다
.forEach((파라미터) -> {코드})
각 인덱스의 값을 파라미터로 넘기고 코드를 수행
(값마다 다른 메소드를 수행한다거나 할때 사용)
map과 forEach는 흡사하지만
map은 값만 바꿔주는 정도고
forEach는 if else나 메소드 등을 사용한느 것이 중점이 되겠다
.anyMatch((파라미터) -> {코드})
.noneMatch((파라미터) -> {코드})
.allMatch((파라미터) -> {코드})
anyMatch는 스트림 중 하나의 값이라도 조건에 맞으면 true
noneMatch는 스트림 중 하나의 값도 조건에 맞지 않으면 true
allMatch는 스트림의 값이 모두 조건에 맞아야 true
.filter(파라미터) -> {코드})
코드에 맞는 값만 가져온다
.reduce(값, 데이터타입::sum)
스트림의 값을 모두 하나로 합칠때 사용하는데
데이터타입과 sum으로 하나로 합친 뒤
마지막에 값을 더해서 가져오게 된다
(String의 경우에는 값, String::concat을 사용)
가공의 경우에는 내용이 많기 때문에
항목마다 모두 예제를 만들어놓지 않았는데
위에도 써놨다시피
이것만 보고 어떻게 만들어가 아니라
맨 아래에 예제 코드가 있으므로
하다가 막히면 그걸 봐주면 된다
반환
- 가공한 값을 원하는 형태로 가져오기

이제 가공까지 했으면 실제 사용할 수 있도록
값을 가져와야 하는데
System.out.println 으로 값을 찍어봤을 때
위와 같이 나온다면 정상적인 값이 나올 수 있도록
반환 작업을 해줘야 하는데

값이 하나만 있는 경우라면
.g를 입력한 후 ctrl + space를 하면 나오는
위와 같이 get(), getAsInt() 등으로 가져올 수 있고
배열, 컬렉션(List, Set, Map) 형태로 가져오는 경우라면
배열의 경우에는 끝에
.toArray();
나머지는
.collect(Collectors.toList());
에서 List만 Set, Map으로 바꿔주면 된다
다른 반환 방법으로는 다음과 같은데
반환방법도 글 맨 아래에 사용방법 및 예제 코드를
써 놨으니까 보다가 막히면 그걸 봐주면 된다
.collect(Collectors.counting());
해당하는 갯수 반환
.collect(Collectors.joining("|"));
모든 값을 합치면서 |를 붙여줌
"" 붙이면 그냥 값만 다 붙이게 됨
.collect(Collectors.averagingInt(val -> Integer.parseInt(val))
.collect(Collectors.averagingDouble(val -> Double.parseDouble(val))
.collect(Collectors.averagingLong(val -> Long.parseLong(val))
값을 int, double, long 형태로 변환한 뒤
double 형태의 평균을 구해 반환
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting())
이름, 갯수의 형태로 Map<String, Long>로 반환을 해 준다
1,1,1,2,2 이렇게 들었으면
"1" , 3 이런식으로 들어간다는 얘기
오라클에서 그룹핑 해서 가져오는 것과 동일한 개념이라고 보면 된다
.collect(Collectors.partitioningBy((파라미터) -> {코드})
조건에 맞으면 true, 아니면 false로 list를 만들고
Map<Boolean, List<String>> 형태로 반환한다
이제 선언, 가공, 반환방법을 알아봤으니
실제 예를 몇개 들어보면
Arrays.stream(arr).boxed().sorted().collect(Collectors.toList())
Arrays.stream(arr) - 선언
.boxed().sorted() - 가공
.collect(Collectors.toList()) - 반환
arr 배열을 정렬 후 List 타입으로 반환
Arrays.stream(arr).findFirst().getAsInt()
Arrays.stream(arr) - 선언
.findFirst() - 가공
.getAsInt() - 반환
arr 배열의 첫번째 값을 int 타입으로 반환
list.stream().skip(1).collect(Collectors.toList())
list.stream() - 선언
.skip(1) - 가공
.collect(Collectors.toList()) - 반환
list명의 첫번째 값은 생략한 뒤 list 타입으로 반환
처음에 딱 보면 뭔가 어려워 보이지만
결국은 동일한 이름의 메소드를
어떻게 붙였다 떼냐 하는 것이기 때문에
개념만 이해한다면 활용하기는 어렵지 않다
이러한 Stream을 사용하면 장점이
1. 사용하기 편하다
스트림을 사용할 줄 알면
머리 굴려가며 이걸 어떻게 해야 원하는 값이 나올까
이런 고민을 덜 해도 되는데
웬만한걸 다 메소드로 구현해 놨기 때문에
메소드만 순서에 맞게 꽂아주면
원하는 값을 쉽게 얻을 수 있다
2. 코드가 짧아진다
for, if else가 내용에 따라
무한하게 늘어나는 것을 생각해보면
Stream은 대부분 다 한줄이고
줄 수가 바뀐다고 한들 가독성을 높이기 위해
. 기준으로 엔터를 치는 정도다
3. 가독성이 높아진다
스트림이 가독성이 뭐가 높은지
이해가 안간다는 사람들이 많은데
기본적으로는 Stream 메소드를 봐도 모르기 때문에
가독성이 뭐가 높은지를 모르는 것이다
그러나 for 돌려가며 중복 값 지우는 것과
distinct() 하나로 지우는 것의 차이가 엄청난 것 처럼
메소드를 읽을 수 있게 되면
s
h
o
w
와 show 정도로
가독성이 차이난다는 것을 알게 된다
단점은
1. 디버그가 힘들다
뭘 잘못 짰거나 에러가 발생한다면
일반 코드의 경우에는 값이 틀어지기 직전,
에러가 나기 직전에 디버그를 걸어놓으면
손쉽게 디버깅이 가능한데
스트림은 한번에 모든 것이 수행되기 떄문에
에러라도 난다고 치면
스트림을 다 뜯어놓고 다시 조립을 해야 한다
가장 문제는 만든 사람이야 그나마 이해가 빠르지만
아예 모르는 사람이 스트림 코드를 디버깅할라면
굉장히 힘들다는 점이다
2. 재활용 불가능
스트림은 한번 쓰면 close 되기 때문에
Stream<> 스트림명 = 값;
이런 식으로 한번 정의해놓고 계속 사용이 불가능하다
즉
Array.stream().~
list.stream.~
이런 식으로 바로 만들어서 사용하게 된다
3. 속도가 느리다

이건 단점이 약간 애매한데
예전에야 Stream 코드가 비효율적이기 때문에
for 도배에 비해 속도가 느렸다지만
요새는 개선이 많이 되어 상당히 따라잡았고
결국 퍼포먼스 비교는
코드를 최적으로 짰을 경우를 두고 비교하는 것인데
일반적으로는 코드를 최적으로 짜는 경우보다는
빙글빙글 돌아가며 짜는 경우도 상당히 많기 때문에
아무리 기본 속도가 빠르건 간에
만드는 사람이 돌아가며 짜기 시작하면
모든 방법이 동일한 스트림보다 느려질 수 있다는 거다
마지막으로 정리해보자면
스트림을 사용하면 배열이나 컬렉션(List, Set, Map) 등을
사용해 원하는 값을 얻으려는 경우
기존의 for 도배를 줄일 수 있고
원하는 값을 메소드만 사용해서 쉽게 가져올 수 있다
다만 디버깅이 힘들다는 것이 흠이 되겠다
'JAVA' 카테고리의 다른 글
| @ModelAttribute 깊이있게 (0) | 2024.08.07 |
|---|---|
| jar와 war의 차이점 및 특징 (0) | 2024.06.26 |
| Java Arrays.sort 오름차순, 내림차순 정렬 (0) | 2024.04.16 |
| Java String관련 메소드 총정리 (0) | 2024.02.09 |
| Stream이란 무엇인가? (0) | 2024.01.02 |