Modern_Java_03(추가 및 수정중)
Mordern Java
서론
원래 순서대로라면 Functional Interface 개념이 먼저 나오는게 맞지만, 상황상 3편부터 스트림에 관련된 내용을 적고 추후에 2편에서 글을 적도록 할 것.
먼저는 코드를 올리고, 추후에 글에 내용을 추가.
- 사실상 자바의 꽃이 아닌가 싶다.
스트림을 처음 볼 때는 난이도가 매우 높아서 좌절을 겪게될것이지만, 하다보면 아에 손도 못댈정도는 아니고, 뭐 어찌저찌 해내게되는 나를 볼 수 있게될것이다.
결국 스트림API도 사람이 논리적인 순서대로 생각한것을 적기위한 도구이기에 차근차근 해나가면 되고, 스트림은 하는만큼 늘어난다는걸 꺠닫게된다.
Streams API
- 자바 8에 나온 개념
- 컬렉션에 대한 작업을 수행하는것이 목적
컬렉션과 스트림 비교
- 스트림은 추가, 삭제, 수정 허용이 안됨.
- 데이터를 추가하려면 다른 방식으로 추가해야함.
- 컬렉션은 인덱스로 get해서 접근이 가능함.
- 스트림은 지연 연산(Lazy Evaluation)를 통해 결과값이 필요할 때까지 계산을 안한다.
- 스트림은 한 번만 사용가능함.
- 스트림은 내부반복을 통해 모든 요소를 반복.
Stream Operations - map
1
2
3
4
5
6
7
List<String> namesUpperCase(List<Student> names){
List<String> namesUpperCase = names.stream() //Stream<Student>
.map(Student::getName) //Stream<String>
.map(String::toUpperCase) // Stream<String> -> UpperCase
.collect(toList()); // returns List // terminal operation
return namesUpperCase;
}
1
2
3
4
5
6
Map<String, Integer> namesLengthMap(ArrayList<String> names){
Map<String, Integer> namesLengthMap = names.stream()//Stream<String>
.collect(toMap(String::toString,String::length)); // returns Map
return namesLengthMap;
Stream Operations - flatMap
1
2
3
4
5
6
7
8
9
10
List<String> printStudentActivities() {
List<String> studentActivities = StudentDataBase.getAllStudents()
.stream()
.map(Student::getActivities) //Stream<List<String>>
.flatMap(List::stream) //<Stream<String>
.collect(toList());
return studentActivities;
1
2
3
4
5
6
7
8
9
10
11
List<String> printUniqueStudentActivities() {
List<String> studentActivities = StudentDataBase.getAllStudents()
.stream()
.map(Student::getActivities)
.flatMap(List::stream)
.distinct()
.sorted()
.collect(toList());
return studentActivities;
1
2
3
4
5
6
7
8
9
10
long getStudentActivitiesCount() {
long totalActivities = StudentDataBase.getAllStudents()
.stream()
.map(Student::getActivities)
.flatMap(List::stream)
.distinct()
.count();
return totalActivities;
Stream Operations - distinct, count, sorted
- distinct
- 중복되는 요소를 제거하는 함수
- count
- 요소의 개수를 반환하는 함수
- sorted
- 요소를 정렬하는 함수
=> 만약 HashSet으로 반환하는것을 사용한다면 순서도 정렬하면서 중복도 제거된다. (상황에 맞게 기능뿐만 아니라 자료구조도 잘 사용하자)
Stream Operations - sorted -> Comparator.comparing
1
2
3
4
5
6
List<Student> sortStudentsByName(){
return StudentDataBase.getAllStudents().stream()
.sorted(Comparator.comparing(Student::getName))
.collect(toList());
}
- sorted(Comparator.comparing(Student::getName)) 에서 특정 요소를 선택해 정렬이 가능함.
Stream Operations - filter
1
2
3
4
5
6
7
8
9
List<Student> filterStudents(){
List<Student> filteredStudentList = StudentDataBase.getAllStudents()
.stream()
.filter(student -> student.getGpa()>=3.9)
.filter(student -> student.getGender().equals("female"))
.collect(toList());
return filteredStudentList;
- 필터를 통해 원하는 조건에 맞는 요소만 처리.
- 반목문에 if문을 통해 원하는 요소만 넣는것과 같은 역할
- 조건이 여러개라면 필터를 여러개 넣으면 가능.
Stream Operations - reduce
1
2
3
4
5
List<Integer> mylist = List.of(1,3,5,7);
int result = mylist.stream
.reduce(1,(a,b) -> a*b);
- a=1, b=1 => a*b 결과 리턴
- a=1, b=3 => a*b 결과 리턴
- a=3, b=5 => a*b 결과 리턴
- a=15, b=7 => a*b 결과 리턴
- 최종연산 결과 105로 반환
1
2
3
4
5
6
String combineStudentNames(){
return StudentDataBase.getAllStudents().stream()
.map(Student::getName)
.distinct()
.reduce("",(a,b) -> a.concat(b)); // performs multiplication for each element in the stream.
1
2
3
4
5
Optional<Student> getHighestGradeStudent(){
Optional<Student> studentOptional = StudentDataBase.getAllStudents().stream()
.reduce((s1,s2)->(s1.getGpa()>s2.getGpa()) ? s1 : s2);
return studentOptional;
Stream Operations - Map + Filter + Reduce Pattern
1
2
3
4
5
myList.stream()
.filter(조건1)
.filter(조건2)
.map(Student::getNoteBo0ok)
.reduce(0, Integer::sum);
- reduce의 2번째 파라미터에 sum, max를 통해 a+b, a>b 등을 직접 구현안해도된다.
- 매핑하기전에 filter의 조건을 추가해 map을 줄이는 방법
Stream Operations - max + reduce
1
2
3
4
5
6
7
8
9
List<Integer> myList = List.of(5,6,7,8,9);
myList.stream()
.reduce(0,(x,y) -> x < y ? x : y);
// 5 -> y
// 6 -> y
// 7 -> y
// 8 -> y
// 9 -> y
Stream Operations - min + reduce
1
2
3
4
5
6
7
8
9
List<Integer> myList = List.of(5,6,7,8,9);
myList.stream()
.reduce(0,(x,y) -> x < y ? x : y);
// 5 -> y
// 6 -> y
// 7 -> y
// 8 -> y
// 9 -> y
Stream Operations - limit, skip
1
2
3
4
5
Optional<Integer> skip(List<Integer> integers){
return integers.stream()
.limit(3)
.reduce((a,b)-> a+b);
}
1
2
3
4
5
Optional<Integer> skip(List<Integer> integers){
return integers.stream()
.skip(3)
.reduce((a,b)-> a+b);
}
Stream Operations - anyMatch, allMatch, noneMatch
1
2
boolean result = StudentDataBase.getAllStudents().stream()
.allMatch(student -> student.getGpa()>=3.9);
1
2
boolean result = StudentDataBase.getAllStudents().stream()
.anyMatch(student -> student.getGpa()>=3.9);
1
2
boolean result = StudentDataBase.getAllStudents().stream()
.noneMatch(student -> student.getGpa()>=3.9);
- anyMatch: 하나의 속성이 있는지 확인해서 있으면 true를 반환함.
- allMatch: 전부다 맞아야 true를 반환.
- noneMatch: 하나라도 없으면 true를 반환함.
Stream Operations - findAny, findFirst
1
2
3
4
5
6
Optional<Student> findAny(){
return StudentDataBase.getAllStudents().stream()
.filter(student -> student.getGpa()>=3.8)
.findAny();
}
1
2
3
4
5
Optional<Student> findFirst(){
return StudentDataBase.getAllStudents().stream()
.filter(student -> student.getGpa()>=3.8)
.findFirst();
- findAny: 사용자가 요청 값을 찾으면 반환.
findFirst: 사용자가 요청 값의 첫번째로 찾은것을 바로 반환.
가장 중요한 차이가 있는데, 병렬로 처리할 때 findany로 찾게되면 병렬로 실행된 것중 여러개의 병렬처리중 가장 먼저 된 값을 찾게되서 실행마다 값이 달라질 수 있음.
Stream Operations - 작성중
Stream Operations - 작성중
출처
Modern Java - Learn Java 8 Features By coding it
https://github.com/ckddn9496/modern-java-in-action
This post is licensed under CC BY 4.0 by the author.