본문으로 건너뛰기

스트림 기본

스트림은 기본적으로 시작연산, 중간연산, 최종연산 세가지를 조합해서 많이 쓴다.
중간연산은 스트림을 반환하므로 여기에 이어서 메서드 체이닝이 가능하다.
스트림은 한번만 사용이 가능하다. 다시 무언가를 하고 싶다면 또다른 스트림을 생성해서 쓰면 된다.
최종연산 스트림을 사용 할 경우 그 시점에서 스트림이 종료(클로즈)되어버린다. forEach, reduce, count등..

  • 시작연산 stream()으로 시작한다(스트림 생성)
  • 중간연산 filter, count, map, sorted, peek 등등
  • 최종연산 forEach, reduce, findFirst, findAny, anyMatch, allMatch, collect등등

실무에서 많이 쓰이니 일단 주요 메서드는 정리하자

  • of 지정한 값으로부터 스트림을 생성
  • count 스트림의 요소수를 리턴
  • distinct 중복값 제거
  • forEach 이터레이터
  • filter 필터링
  • concat 두개의 스트림을 붙인다
  • map 스트림 요소를 변환한다
  • mapToDouble 스트림 요소를 더블형으로 변환하고 DoubleStream을 리턴한다
  • mapToInt 스트림 요소를 int형으로 변환하고 IntStream을 리턴한다
  • mapToLong 스트림 요소를 long형으로 변환하고 LongStream을 리턴한다
  • flatMap 스트림 요소를 변환하여 flat하게 한다
  • allMatch 스트림의 모든 요소가 조건에 부합하는지 안하는지
  • anyMatch 스트림의 요소가 하나만이라도 조건에 부합하는지 안하는지
  • noneMatch 조건에 부합하지 않는지
  • reduce 스트림의 요소를 집계
  • sorted 스트림 요소 정렬
  • collect 스트림 요소의 집계 혹은 컬렉션으로 변환
  • toArray 스트림을 배열로 변환
  • iterate 무한값을 반환하는 스트림을 생성
  • limit 지정한 조건수 만큼 반환
  • parallelStream 병렬처리 스트림
  • sequential 병렬처리가 가능한 스트림에서 시퀀셜 스트림으로

기본연습

중복값을 제거한 카운트 값을 출력

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Apple");

long distinctCount = fruits.stream().distinct().count();
System.out.println(distinctCount);

}
}
4

요소를 순회(메서드 참조형으로 출력)

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

fruits.stream().forEach(System.out::println);
}
}
Orange
Apple
Kiwi
Banana
Mango

요소를 순회(람다식으로 출력)

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

fruits.stream().forEach(s -> System.out.println(s));
}
}
Orange
Apple
Kiwi
Banana
Mango

복합

public class Exercise1 {

public static void main(String[] args) {

List<String> devLang = Arrays.asList("Javascript", "C++", "Golang", "Java", "C#");

devLang.stream()
.filter(s -> s.startsWith("J")) // 앞글자가 J인것만 필터링
.map(s -> s.toUpperCase()) // 각 요소의 문자를 대문자로 변환
.sorted((a, b) -> a.length() - b.length()) // 문자수가 적은순으로 정렬
.forEach(System.out::println);
}
}
JAVA
JAVASCRIPT

IntStream으로 변환

import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Exercise1 {

public static void main(String[] args) {

Stream<String> devLang = Stream.of("Javascript", "C++", "Golang", "Java", "C#");

IntStream intStreamDevLang = devLang.mapToInt(s -> s.length());

intStreamDevLang.forEach(System.out::println);

}
}
10
3
6
4
2

스트림의 요소수 파악

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

Stream<String> fruitsStream = fruits.stream();

long fruitsCount = fruitsStream.count();

System.out.println(fruitsCount);

}
}
5

위에 코드 이렇게 써도 됨

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

long fruitsCount = fruits.stream().count();

System.out.println(fruitsCount);

}
}

스트림의 필터

public class Exercise1 {

public static void main(String[] args) {

List<String> names = Arrays.asList("Cavin", "Mariah", "James", "Joly", "Mike");

names.stream()
.filter(s -> s.startsWith("J"))
.forEach(s -> System.out.println(s));
}
}
James
Joly

스트림을 연결

public class Exercise1 {

public static void main(String[] args) {

Stream<String> names = Stream.of("Cavin", "Mariah", "James", "Joly", "Mike");
Stream<String> fruits = Stream.of("Apple", "Kiwi", "Orange", "Banana");

Stream<String> namesFruits = Stream.concat(names, fruits);

namesFruits.forEach(System.out::println);
}
}
Cavin
Mariah
James
Joly
Mike
Apple
Kiwi
Orange
Banana

스트림의 요소를 변환

public class Exercise1 {

public static void main(String[] args) {
List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

fruits.stream()
.map(s -> s.length())
.forEach(p -> System.out.println(p));
}
}
6
5
4
6
5

map은 많이 쓰인다. 맵은 각 요소를 변환할때 쓰인다.

특정 문자열로 구분짓는 스트림(flatMap이용)

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange,Apple", "Kiwi,Banana", "Mango");

fruits.stream()
.flatMap(s -> Stream.of(s.split(","))) // 콤마를 기준으로 나눈 스트림을 리턴
.forEach(System.out::println);
}
}
Orange
Apple
Kiwi
Banana
Mango

이건 진짜 실무에서 잘 사용하면 좋을것 같다.

스트림 요소가 조건에 부합하는지 확인

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

boolean result1 = fruits.stream().allMatch(s -> s.startsWith("A"));
System.out.println(result1);

boolean result2 = fruits.stream().anyMatch(s -> s.startsWith("A"));
System.out.println(result2);

boolean result3 = fruits.stream().noneMatch(s -> s.startsWith("A"));
System.out.println(result3);

}
}
false
true
false

스트림 요소의 집계

public class Exercise1 {

public static void main(String[] args) {

IntStream stream = IntStream.of(10, 20, 30, 40, 50);
int sumStream = stream.sum();

System.out.println(sumStream);

}
}
150

스트림을 정렬

public class Exercise1 {

public static void main(String[] args) {

List<String> fruits = Arrays.asList("Orange", "Apple", "Kiwi", "Banana", "Mango");

fruits.stream()
.sorted() // 알파벳 순으로 정렬이 됨!
.forEach(System.out::println);

System.out.println();

fruits.stream()
.sorted((a,b) -> a.length() - b.length()) // 문자열의 길이로 정렬
.forEach(System.out::println);

}
}
Apple
Banana
Kiwi
Mango
Orange

Kiwi
Apple
Mango
Orange
Banana

스트림 요소들을 그룹핑

public class Exercise1 {

public static void main(String[] args) {

List<String> names = Arrays.asList("Cavin", "David", "James", "Cane", "Dorothy");

Map<Character, List<String>> map = names.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));

System.out.println(map.get('J'));
System.out.println(map.get('D'));
System.out.println(map.get('C'));

// 맵 어떻게 생겼는지 구경좀 하자
for(Map.Entry<Character, List<String>> entry : map.entrySet()) {
System.out.println(
"key : " + entry.getKey()
+ " , value : " + entry.getValue());
}
}
}
[James]
[David, Dorothy]
[Cavin, Cane]
key : C , value : [Cavin, Cane]
key : D , value : [David, Dorothy]
key : J , value : [James]

이것도 실무에서 잘 쓰면 유용하니 필히 반복 !!

스트림으로 무한대의 수를 구하기

limit으로 제한을 걸어뒀다. 안걸어두면 안드로메다로 가버림

public class Exercise1 {

public static void main(String[] args) {

Stream<Integer> stream = Stream.iterate(10, i -> i *2);

stream.limit(10).forEach(s -> System.out.println(s));
}
}
10
20
40
80
160
320
640
1280
2560
5120

병렬 스트림

stream()으로 시작하지 않고, parallelStream()으로 시작한다.
IntStream을 parallel()로 받아서 병렬스트림으로 바꾸기도 한다.
처리시간이 길거나, 큰 오브젝트를 다룰때 사용하면 성능향상에 도움이 된다.

public class Exercise1 {

public static void main(String[] args) {

List<String> names = Arrays.asList("Cavin", "David", "James", "Cane", "Dorothy");

names.parallelStream()
.map(s -> s.toUpperCase())
.forEach(System.out::println);

IntStream.range(1, 100)
.parallel()
.filter(i -> i % 2 == 0) // 짝수만을 출력
.forEach(System.out::println);
}
}
JAMES
DOROTHY
CANE
DAVID
CAVIN
16
18
78
80
44
66
82
62
64
8
48
76
.
.
생략

스트림을 컬렉션으로 바꾸기

진짜 유용 + 신기 + 간결 + 꿀잼
new로 다시 넘기거나 생성자 사용하는건 신기신기

public class Exercise1 {

public static void main(String[] args) {

List<String> names = Arrays.asList("Cavin", "David", "James", "Cane", "Dorothy");

// List로 변환
List<String> namesList = names.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toList());

System.out.println("Casting to List : " + namesList);


// Set으로 변환
Set<String> namesSet = names.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toSet());

System.out.println("Casting to Set : " + namesSet);

// 변환후에 클래스 지정도 가능하다
List<String> namesLinkedList = names.stream()
.map(s -> s.toUpperCase())
.collect(Collectors.toCollection(LinkedList::new));

System.out.println("Casting to LinkedList : " + namesLinkedList);

// 문자열을 키로, 문자의 길이를 벨류로 넣는 맵

Map<String, Integer> namesMap = names.stream()
.collect(Collectors.toMap(
s -> s,
s -> s.length()
));

System.out.println("Casting to Map : " + namesMap);


// 스트림을 배열로

Object[] namesArray = names.stream()
.map(s -> s.toUpperCase())
.toArray();

System.out.println("Casting to Array");
for(Object name : namesArray) {
System.out.println(name);
}


// toArray메서드에 배열의 생성자를 지정하면 배열형으로 변환도 가능하다
String[] name = names.stream()
.map(s -> s.toUpperCase())
.toArray(String[]::new);

System.out.println("Casting to Array(Constructor)");
for(int i=0; i < name.length; i++) {
System.out.println(name[i]);
}
}
}
Casting to List : [CAVIN, DAVID, JAMES, CANE, DOROTHY]
Casting to Set : [DOROTHY, CAVIN, JAMES, DAVID, CANE]
Casting to LinkedList : [CAVIN, DAVID, JAMES, CANE, DOROTHY]
Casting to Map : {Dorothy=7, Cavin=5, James=5, David=5, Cane=4}
Casting to Array
CAVIN
DAVID
JAMES
CANE
DOROTHY
Casting to Array Constructor
CAVIN
DAVID
JAMES
CANE
DOROTHY

실무. 리스트형 맵 오브젝트 일때 정리

실무에서 많이 쓰는 리스트 형의 맵 오브젝트 형이다. DB에서 데이터를 bean으로 뽑아오지 않고
그냥 리스트 맵형으로 뽑아올때가 종종 있는데. 문제는 뽑아오고 나서 자바단에서 리스트맵을 필요한 값으로만 재정렬 할 때 사용한다.
만약 NullPoint에러가 발생한다면 두번째 방식인 map.containsValue스타일로 써주면 된다.
어떤 특정 값 만을 갖고있는 리스트로 재정렬 하고 싶을때! 이렇게 써보자

public class StreamListMap {

public static void main(String[] args) {
Map<String, Object> members1 = new HashMap<>();
Map<String, Object> members2 = new HashMap<>();
Map<String, Object> members3 = new HashMap<>();
Map<String, Object> members4 = new HashMap<>();
Map<String, Object> members5 = new HashMap<>();

members1.put("Name", "James");
members1.put("Location", "Seoul");

members2.put("Name", "David");
members2.put("Location", "Tokyo");

members3.put("Name", "Lucy");
members3.put("Location", "New York");

members4.put("Name", "Cavin");
members4.put("Location", "Seoul");

members5.put("Name", "Alex");
members5.put("Location", "New York");


List<Map<String, Object>> members = new ArrayList<>();

members.add(members1);
members.add(members2);
members.add(members3);
members.add(members4);
members.add(members5);

List<Map<String, Object>> memberList =
members.stream()
.filter(map -> map.entrySet().stream().anyMatch (e->e.getValue().equals("Tokyo")))
.collect(Collectors.toList());

System.out.println("memberList : " + memberList);

// 위의 방식이 NullPoint에러일 경우에는 이렇게도 가능하다
List<Map<String, Object>> memberList2 =
members.stream()
.filter(map -> map.containsValue("Seoul"))
.collect(Collectors.toList());

System.out.println("memberList2 : " + memberList2);

}

}
memberList : [{Name=David, Location=Tokyo}]
memberList2 : [{Name=James, Location=Seoul}, {Name=Cavin, Location=Seoul}]