[Java] Stream 이란?
- 참고사이트
Stream 이란?
Stream
은 Java8 부터 지원
하며, 컬렉션과 배열 등에 저장 된 요소들을 하나씩 참조하며 반복적인 처리를 가능하게 하는 기능이다.
-> Stream 을 사용하면 우리가 for 문을 이용해 처리하던 걸 간단하고 클린하게 작성 할 수 있게 된다.
JAVA8 에서는 아래와 같이 요악하고 있다.
- 선언형
- 간결하고 가독성이 좋아진다
- 조립할 수 있다.
- 유연성이 좋아진다.
- 병렬화
- 성능이 좋아진다.
사용방법
1
2
3
4
5
6
7
8
LinkedList<Integer> dataList = new LinkedList<Integer>() {
{
Random random = new Random();
for(int i=0; i<100; i++) {
add(random.nextInt(100));
}
}
};
기존코드
위와 같은 데이터가 있을 때 우리가 기존에 사용하던 방법은 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// dataList 의 값을 정렬하고
Collections.sort(dataList, new Comparator<Integer>() {
@Override
public int compare(Integer arg0, Integer arg1) {
return arg1.compareTo(arg0);
}
});
// 반복을 돌면서 가장 큰 7의 배수 4개를 출력한다.
for (int i=0, count=0, size=dataList.size(); i<size && count<4; ++i) {
if (dataList.get(i) % 7 == 0) {
System.out.println(dataList.get(i));
++count;
}
};
Stream 사용
1
2
3
4
5
dataList.stream()
.filter((a) -> a % 7 == 0) // 중간연산 - 7의 배수인 요소만 필터링
.sorted((a, b) -> b.compareTo(a)) // 중간연산 - 정렬
.limit(4) // 중간연산 - 4개만 찾기
.forEach(System.out::println); // 최종연산 - 출력
보기 쉽게 줄바꿈을 했지만, 라인수가 무척이나 줄어들게 된다. 만족스럽다.
이와 같이 Stream 을 이용하면 단순히 비지니스 처리를 선언으로 하기 때문에 쉽게 구현
할 수 있으며, 각각의 블럭 (sorted나 filter) 등이 chain 형식을 지원하기 때문에 복잡한 로직에 대해 가독성과 명확성
을 확실시 해줄 수 있을 것같다. (즉 파이프라인 구조이다.)
또한 내부적으로는 데이터 처리과정을 병렬화할 수 있기 때문에 성능을 더 좋게 만들 수 있다. (물론 병렬을 위한 thread 처리에 대해서는 신경쓰지 않아도 된다.)
샘플코드
List 에서 데이터 꺼내기
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// List<String> 에서 String 타입 데이터 꺼내기
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(Arrays.asList("Apple","Banana","Melon","Grape","Strawberry"));
System.out.println(list.stream().filter(t->t.length()>5).collect(Collectors.joining(" "))); //Banana Strawberry
System.out.println(list.stream().filter(t->t.length()>5).collect(Collectors.toList())); //[Banana, Strawberry]
}
// List<Map<String, Object>> 에서 첫번째 Map 꺼내기
Optional<Map<String, Object>> tempMap = StreamSupport.stream(tempList.spliterator(), false)
.map(map -> map)
.filter(map -> !map.isEmpty())
.filter(map -> map.get("tempKey") != null)
.findFirst();
// List<Map<String, Object>> 에서 특정 value와 일치하는 map 만 꺼내기
private Map<String, Object> getMap(List<Map<String, Object>> tempList, String tempValue) {
return StreamSupport.stream(tempList.spliterator(), false)
.map(tempMap -> tempMap)
.filter(tempMap -> !tempMap.isEmpty())
.filter(tempMap -> !tempMap.get("temp_key").toString().isBlank())
.filter(tempMap -> tempMap.get("temp_key").toString().equals(tempValue))
.findFirst()
.orElseThrow(() -> new NullPointerException("NPE"));
}
// List<Map<String, Object>> 에서 특정 Key 의 Value 를 모두 꺼내기
private String getValueToString(List<Map<String, Object>> tempList, String key) {
return StreamSupport.stream(tempList.spliterator(), false)
.map(map -> map)
.filter(map -> !map.isEmpty())
.filter(map -> !map.get(key).toString().isBlank())
.map(map -> map.get(key).toString())
.collect(Collectors.joining("연결문자"));
}
String arrayValue = getKeyToString(tempList, key);
List<String> seatsNumber = Arrays.asList(arrayValue.split("자를문자"));
Map 에서 데이터 꺼내기
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// key 를 이용한 value 꺼내기
public static void main(String[] args) {
Map<String, Integer> books = new HashMap<>();
books.put("JSP 프로그래밍", 50);
books.put("자바 프로그래밍", 100);
books.put("Javascript 프로그래밍", 0);
// value 값을 이용 한 key 추출
// value 가 0 인 데이터 추출
Optional<String> optBooks = books.entrySet().stream()
.filter(e -> e.getValue() == 0)
.map(Map.Entry::getKey)
.findFirst();
// assertEquals("Javascript 프로그래밍", optBooks.get());
System.out.println("optBooks.get() : "+optBooks.get());
// key 값을 이용한 value 추출
Optional<Integer> stock = books.entrySet().stream()
.filter(e -> e.getKey().startsWith("JSP"))
.map(Map.Entry::getValue)
.findFirst();
System.out.println("stock.get() : "+stock.get());
// assertEquals(50, stock.get());
}
// Map 에서 String 꺼내기
private String getEntryValueToString(Map<String, Object> entry, String key) {
return entry.entrySet().stream()
.filter(e -> !entry.isEmpty())
.filter(e -> entry.get(key) != null)
.filter(e -> e.getKey().equals(key))
.map(e -> e.getValue().toString())
.findFirst()
.orElseThrow(() -> new NullPointerException("NPE"));
}
// 특정 value 만 변환하기
private Map<String, Object> conversionValue(Map<String, Object> tempMap) {
return tempMap.entrySet().stream()
.filter(e -> !tempMap.isEmpty())
.filter(e -> tempMap.get("tempKey") != null)
.map(e -> {
if(e.getKey().equalsIgnoreCase("tempKey")) {
e.setValue("변경할 값");
}
return e;
})
.collect(HashMap::new, (map, entry) -> map.put(entry.getKey(), entry.getValue()), HashMap::putAll);
}
List<Map<String,Object» 정렬하기
1
2
3
4
5
6
// createDate 의 값을 비교하여 정렬
List<Map<String, Object>> list = tempList.stream()
.sorted((currentMap, nextMap) ->
(currentMap.get("createDate"))
.compareTo(nextMap.get("createDate"))
).collect(Collectors.toList());
List 중복 데이터 제거하기
1
2
3
4
List<String> beforeList = new ArrayList<>(Arrays.asList("Apple","Banana","Melon","Grape", "Apple", "Strawberry"));
System.out.println("before : "+beforeList);
List<String> afterList = beforeList.stream().distinct().collect(Collectors.toList());
System.out.println("after : "+afterList);
Leave a comment