반응형
최종연산의 종류
1. 최종연산
2. collect()
3. reduce()
4. groupingBy(), partitioningBy()
Optional<T>와 OptionalInt
- T타입의 객체를 감싸는 래퍼클래스
: Optional객체에 모든 타입의 참조변수를 담아서 반환 - Optional 메서드를 통해 null체크가 가능하다.
- Optional 객체 생성
- of();
- ofnullable();
: 널로 객체 생성 가능 - empty()
: 빈 객체로 초기화 가능
- Optional 객체의 값 가져오기
- get();
- orElse("");
: null일 경우 기본값 설정가능- orElseGet()
- orElseGet(String::new)
:null일때 대체값 반환
- orElseGet(String::new)
- orElseThrow()
- orElseThrow(NullPointerException::new)
:null일때 예외 발생
- orElseThrow(NullPointerException::new)
- orElseGet()
- filter(), map(), flatMap() 사용시 null일 경우 메서드 작동안함
: 예외처리 가능 -> null일경우 -1 반환
result=Optional.of("")
.filter(x->x.length()>0)
.map(Integer::parseInt).orElse(-1); - null 체크 메서드
- isPresent()
:null이면 false, 아니면 true 반환 - 값이 존재하면 람다식 실행, 없으면 작동안함
- isPresent()
- Optional를 반환하는 최종연산들
- findAny()
- findFirst()
- max()
- min()
- reduce()
- Optional<T> 반환하는 get()메서드
- OptionalInt 반환하는 getAsInt()메서드
- OptionalLong 반환하는 getAsLong()메서드
- OptionalDouble 반환하는 getAsDouble()메서드
1. 최종 연산 메서드
1. forEach()
2. 조건 검사 - boolean
: allMatch(), anyMatch(), noneMatch(), findFirst(), findAny()
3. 통계 - Long / Optional<T> 로 이루어진 리턴타입
: count() / sum(), average(), max(), min()
4. 리듀싱 - 초기값 identity / 연산 방법 BinaryOperator() 으로 이루어진 매개변수 이용
: reduce()
미리 작성된 reduce()메서드
(1) int count = intStream.reduce(0, (a,b) -> a+1);
(2) int sum = intStream.reduce(0, (a,b) -> a+b);
(3) int max = intStream.reduce(Integer.MIN_VALUE(a,b) -> a>b ? a:b);
-> intStream.reduce(Integer::max);
(4) int min = intStream.reduce(Integer.MAX_VALUE(a,b) -> a<b ? a:b);
-> intStream.reduce(Integer::min);
package lamdaAndstream;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Stream4 {
public static void main(String[] args) {
String[] strArr = {
"Inheritance", "Java", "Lambda", "stream",
"OptionalDouble", "IntStream", "count", "sum"
};
//1. 스트림 출력
//2. 스트림 비었는지 확인하는 noEmptyStr
//3. 배열로 스트림 만들어 Optional<T> 객체 sWord로 생성해, 조건 필터링
System.out.println("noEmptyStr="+noEmptyStr);
System.out.println("sWord="+ sWord.get());
//Stream<String[]>을 IntStream으로 변환
IntStream intStream1 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream2 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream3 = Stream.of(strArr).mapToInt(String::length);
IntStream intStream4 = Stream.of(strArr).mapToInt(String::length);
//4. 통계정보를 reduce로 만들기
//(1) 총계
//(2) 총합
//5. OptionalInt를 반환형으로 통계 정보를 reduce로 만들기
//(3) 최댓값
//(4) 최솟값
System.out.println("count="+count);
System.out.println("sum="+sum);
System.out.println("max="+ max.getAsInt());
System.out.println("min="+ min.getAsInt());
}
}
//1.
Stream.of(strArr).forEach(System.out::println);
//2.
boolean noEmptyStr = Stream.of(strArr).noneMatch(s->s.length()==0);
//3.
Optional<String> sWord = Stream.of(strArr)
.filter(s->s.charAt(0)=='s').findFirst();
//4.
int count = intStream1.reduce(0, (a,b) -> a + 1);
int sum = intStream2.reduce(0, (a,b) -> a + b);
//5.
OptionalInt max = intStream3.reduce(Integer::max);
OptionalInt min = intStream4.reduce(Integer::min);
2.collect()
collect() : 스트림의 최종연산. 매개변수로 컬렉터를 필요로 한다.
Collector : 인터페이스로, 컬렉터가 구현해야하는 인터페이스
Collectors : 클래스로, static메서드를 통해 미리 작성된 컬렉터 제공
static 메서드로 작성된 컬렉터
1. 스트림을 컬렉션과 배열로 변환 - 배열로 변환시 생성자의 리턴타입 제공해야 Object[]로 반환되지 않는다.
: toList(), toSet(), toMap(), toCollection(), toArray()
2. 통계 - groupingBy()와 함께 사용하기 위한 메서드
: counting(), summingInt(),[팩토리 메서드 summarizingInt()], averagingInt(), maxBy(), minBy()
3. 리듀싱 - IntStream은 collect()가 매개변수 3개 / Stream<Integer>는 collect()가 매개변수 1개
: reducing()
4. 문자열 결합 - map()을 이용해 스트림의 요소를 문자열로 변환
: joining()
package lamdaAndstream;
import java.util.*;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.joining;
public class Stream5 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("이자바", 3, 300),
new Student("김자바", 1, 200),
new Student("안자바", 2, 100),
new Student("박자바", 2, 150),
new Student("소자바", 1, 200),
new Student("나자바", 3, 290),
new Student("감자바", 3, 180)
};
//1. 학생 이름만 뽑아서 List<String> names에 저장
//-> collct를 이용해 추출
System.out.println(names);
//2. 스트림을 배열 stuArr2로 변환
for(Student s : stuArr2)
System.out.println(s);
//3. 스트림을 Map<String, Student> stuMap로 변환. 학생 이름이 key
for(String name : stuMap.keySet())
System.out.println(name +"-"+stuMap.get(name));
//4. collect를 이용한 통계 메서드
//(1) 총계
//(2) 총합
System.out.println("count="+count);
System.out.println("totalScore="+totalScore);
//5. 총합을 collect메서드를 통한 리듀싱해, totalScore의 합계
System.out.println("totalScore="+totalScore);
//6. 최고의 학생 Optional<Student> topStudent 객체 생성
//-> 학생들의 총점을 비교해 가장 큰 학생 추출
System.out.println("topStudent="+topStudent.get());
//7. 통계 메서드 stat에서 collect 메서드의 팩토리메서드를 통해, 출력
System.out.println(stat);
//8. 학생 이름을 문자열 결합해 stuNames에 넣고, 출력
System.out.println(stuNames);
}
}
class Student implements Comparable<Student> {
String name;
int ban;
int totalScore;
Student(String name, int ban, int totalScore) {
this.name =name;
this.ban =ban;
this.totalScore =totalScore;
}
public String toString() {
return String.format("[%s, %d, %d]", name, ban, totalScore).toString();
}
String getName() { return name;}
int getBan() { return ban;}
int getTotalScore() { return totalScore;}
public int compareTo(Student s) {
return s.totalScore - this.totalScore;
}
}
// 학생 이름만 뽑아서 List<String>에 저장
List<String> names = Stream.of(stuArr).map(Student::getName)
.collect(Collectors.toList());
// 스트림을 배열로 변환
Student[] stuArr2 = Stream.of(stuArr).toArray(Student[]::new);
// 스트림을 Map<String, Student>로 변환. 학생 이름이 key
Map<String,Student> stuMap = Stream.of(stuArr)
.collect(Collectors.toMap(s->s.getName(), p->p));
long count = Stream.of(stuArr).collect(counting());
long totalScore = Stream.of(stuArr)
.collect(summingInt(Student::getTotalScore));
totalScore = Stream.of(stuArr)
.collect(reducing(0, Student::getTotalScore, Integer::sum));
Optional<Student> topStudent = Stream.of(stuArr)
.collect(maxBy(Comparator.comparingInt(Student::getTotalScore)));
IntSummaryStatistics stat = Stream.of(stuArr)
.collect(summarizingInt(Student::getTotalScore));
String stuNames = Stream.of(stuArr)
.map(Student::getName)
.collect(joining(",", "{", "}"));
4. 그룹화와 분할
: 스트림의 요소를 특정 기준으로 그룹화
: 스트림의 요소를 지정된 조건에 일치하는 그룹과 일치하지 않는 그룹으로 분할
-> groupingBy() : Function
-> partitioningBy() : Predicate
리턴타입은 Map
|
(1) partitioningBy()를 이용한 분류
package lamdaAndstream;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.*;
import static java.util.stream.Collectors.partitioningBy;
class Student {
String name;
boolean isMale; // 성별
int hak; // 학년
int ban; // 반
int score;
Student(String name, boolean isMale, int hak, int ban, int score) {
this.name = name;
this.isMale = isMale;
this.hak = hak;
this.ban = ban;
this.score = score;
}
String getName() { return name;}
boolean isMale() { return isMale;}
int getHak() { return hak;}
int getBan() { return ban;}
int getScore() { return score;}
public String toString() {
return String.format("[%s, %s, %d학년 %d반, %3d점]",
name, isMale ? "남":"여", hak, ban, score);
}
// groupingBy()에서 사용
enum Level { HIGH, MID, LOW } // 성적을 상, 중, 하 세 단계로 분류
}
public class Stream6 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("나자바", true, 1, 1, 300),
new Student("김지미", false, 1, 1, 250),
new Student("김자바", true, 1, 1, 200),
new Student("이지미", false, 1, 2, 150),
new Student("남자바", true, 1, 2, 100),
new Student("안지미", false, 1, 2, 50),
new Student("황지미", false, 1, 3, 100),
new Student("강지미", false, 1, 3, 150),
new Student("이자바", true, 1, 3, 200),
new Student("나자바", true, 2, 1, 300),
new Student("김지미", false, 2, 1, 250),
new Student("김자바", true, 2, 1, 200),
new Student("이지미", false, 2, 2, 150),
new Student("남자바", true, 2, 2, 100),
new Student("안지미", false, 2, 2, 50),
new Student("황지미", false, 2, 3, 100),
new Student("강지미", false, 2, 3, 150),
new Student("이자바", true, 2, 3, 200)
};
System.out.printf("1. 단순분할(성별로 분할)%n");
for(Student s : maleStudent) System.out.println(s);
for(Student s : femaleStudent) System.out.println(s);
System.out.printf("%n2. 단순분할 + 통계(성별 학생수)%n");
System.out.println("남학생 수 :"+ stuNumBySex.get(true));
System.out.println("여학생 수 :"+ stuNumBySex.get(false));
System.out.printf("%n3. 단순분할 + 통계(성별 1등)%n");
//1. 리턴타입이 Optional<Student> 인 topScoreBySex
System.out.println("남학생 1등 :"+ topScoreBySex.get(true));
System.out.println("여학생 1등 :"+ topScoreBySex.get(false));
//2. 리턴타입이 Student인 topScoreSex2
System.out.println("남학생 1등 :"+ topScoreBySex2.get(true));
System.out.println("여학생 1등 :"+ topScoreBySex2.get(false));
System.out.printf("%n4. 다중분할(성별 불합격자, 100점 이하)%n");
for(Student s : failedMaleStu) System.out.println(s);
for(Student s : failedFemaleStu) System.out.println(s);
}
}
System.out.printf("1. 단순분할(성별로 분할)%n");
Map<Boolean, List<Student>> stuBySex = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale));
List<Student> maleStudent = stuBySex.get(true);
List<Student> femaleStudent = stuBySex.get(false);
System.out.printf("%n2. 단순분할 + 통계(성별 학생수)%n");
Map<Boolean, Long> stuNumBySex = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale, counting()));
System.out.printf("%n3. 단순분할 + 통계(성별 1등)%n");
//(1)
Map<Boolean, Optional<Student>> topScoreBySex = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale,
maxBy(comparingInt(Student::getScore))
));
//(2)
Map<Boolean, Student> topScoreBySex2 = Stream.of(stuArr)
.collect(partitioningBy(Student::isMale,
collectingAndThen(
maxBy(comparingInt(Student::getScore)), Optional::get
)
));
System.out.printf("%n4. 다중분할(성별 불합격자, 100점 이하)%n");
Map<Boolean, Map<Boolean, List<Student>>> failedStuBySex =
Stream.of(stuArr).collect(partitioningBy(Student::isMale,
partitioningBy(s -> s.getScore() <= 100))
);
List<Student> failedMaleStu = failedStuBySex.get(true).get(true);
List<Student> failedFemaleStu = failedStuBySex.get(false).get(true);
(2) groupingBy()를 이용한 분류
|
package lamdaAndstream;
import java.util.*;
import java.util.Optional;
import java.util.stream.Stream;
import static java.util.Comparator.comparingInt;
import static java.util.stream.Collectors.*;
class Student {
String name;
boolean isMale; // 성별
int hak; // 학년
int ban; // 반
int score;
Student(String name, boolean isMale, int hak, int ban, int score) {
this.name = name;
this.isMale = isMale;
this.hak = hak;
this.ban = ban;
this.score = score;
}
String getName() { return name;}
boolean isMale() { return isMale;}
int getHak() { return hak;}
int getBan() { return ban;}
int getScore() { return score;}
public String toString() {
return String.format("[%s, %s, %d학년 %d반, %3d점]", name, isMale ? "남":"여", hak, ban, score);
}
enum Level {
HIGH, MID, LOW
}
}
public class Stream7 {
public static void main(String[] args) {
Student[] stuArr = {
new Student("나자바", true, 1, 1, 300),
new Student("김지미", false, 1, 1, 250),
new Student("김자바", true, 1, 1, 200),
new Student("이지미", false, 1, 2, 150),
new Student("남자바", true, 1, 2, 100),
new Student("안지미", false, 1, 2, 50),
new Student("황지미", false, 1, 3, 100),
new Student("강지미", false, 1, 3, 150),
new Student("이자바", true, 1, 3, 200),
new Student("나자바", true, 2, 1, 300),
new Student("김지미", false, 2, 1, 250),
new Student("김자바", true, 2, 1, 200),
new Student("이지미", false, 2, 2, 150),
new Student("남자바", true, 2, 2, 100),
new Student("안지미", false, 2, 2, 50),
new Student("황지미", false, 2, 3, 100),
new Student("강지미", false, 2, 3, 150),
new Student("이자바", true, 2, 3, 200)
};
System.out.printf("1. 단순그룹화(반별로 그룹화)%n");
for(List<Student> ban : stuByBan.values()) {
for(Student s : ban) {
System.out.println(s);
}
}
System.out.printf("%n2. 단순그룹화(성적별로 그룹화)%n");
//1. Map으로 그룹화
//2. TreeSet<>으로 키셋만들기
for(Student.Level key : keySet) {
System.out.println("["+key+"]");
for(Student s : stuByLevel.get(key))
System.out.println(s);
System.out.println();
}
System.out.printf("%n3. 단순그룹화 + 통계(성적별 학생수)%n");
for(Student.Level key : stuCntByLevel.keySet())
System.out.printf("[%s] - %d명, ", key, stuCntByLevel.get(key));
System.out.println();
/*
for(List<Student> level : stuByLevel.values()) {
System.out.println();
for(Student s : level) {
System.out.println(s);
}
}
*/
System.out.printf("%n4. 다중그룹화(학년별, 반별)%n");
for(Map<Integer, List<Student>> hak : stuByHakAndBan.values()) {
for(List<Student> ban : hak.values()) {
System.out.println();
for(Student s : ban)
System.out.println(s);
}
}
System.out.printf("%n5. 다중그룹화 + 통계(학년별, 반별 1등)%n");
for(Map<Integer, Student> ban : topStuByHakAndBan.values())
for(Student s : ban.values())
System.out.println(s);
System.out.printf("%n6. 다중그룹화 + 통계(학년별, 반별 성적그룹)%n");
//1. Map으로 그룹화
//2. Set으로 키셋 만들기
for(String key : keySet2) {
System.out.println("["+key+"]" + stuByScoreGroup.get(key));
}
} // main의 끝
}
System.out.printf("1. 단순그룹화(반별로 그룹화)%n");
Map<Integer, List<Student>> stuByBan = Stream.of(stuArr)
.collect(groupingBy(Student::getBan));
System.out.printf("%n2. 단순그룹화(성적별로 그룹화)%n");
Map<Student.Level, List<Student>> stuByLevel = Stream.of(stuArr)
.collect(groupingBy(s-> {
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
}));
TreeSet<Student.Level> keySet = new TreeSet<>(stuByLevel.keySet());
System.out.printf("%n3. 단순그룹화 + 통계(성적별 학생수)%n");
Map<Student.Level, Long> stuCntByLevel = Stream.of(stuArr)
.collect(groupingBy(s-> {
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
}, counting()));
*/
System.out.printf("%n4. 다중그룹화(학년별, 반별)%n");
Map<Integer, Map<Integer, List<Student>>> stuByHakAndBan =
Stream.of(stuArr)
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan)
));
System.out.printf("%n5. 다중그룹화 + 통계(학년별, 반별 1등)%n");
Map<Integer, Map<Integer, Student>> topStuByHakAndBan = Stream.of(stuArr)
.collect(groupingBy(Student::getHak,
groupingBy(Student::getBan,
collectingAndThen(
maxBy(comparingInt(Student::getScore)),
Optional::get
)
)
));
System.out.printf("%n6. 다중그룹화 + 통계(학년별, 반별 성적그룹)%n");
Map<String, Set<Student.Level>> stuByScoreGroup = Stream.of(stuArr)
.collect(groupingBy(s-> s.getHak() + "-" + s.getBan(),
mapping(s-> {
if(s.getScore() >= 200) return Student.Level.HIGH;
else if(s.getScore() >= 100) return Student.Level.MID;
else return Student.Level.LOW;
} , toSet())
));
Set<String> keySet2 = stuByScoreGroup.keySet();
5. Optional 객체
package lamdaAndstream;
import java.util.OptionalInt;
public class Optional {
public static void main(String[] args) {
//1. 문자열 abcde로 Optional<String> 생성
//2. int 문자열 길이로 Optional<Integer> 생성
System.out.println("optStr="+optStr.get());
System.out.println("optInt="+optInt.get());
//1. 문자열 123을 이용해 Optional 객체 생성
//2. 길이가 0보다 크면 필터링
//3. Int로 변환해 int result1에 삽입
//1. 비어있는 문자열을 이용해 Optional 객체 생성
//2. 길이가 0보다 크면 필터링
//3. Int로 변환해 int result2에 삽입하는데 null이면 -1
System.out.println("result1="+result1);
System.out.println("result2="+result2);
//1. 문자열 456을 이용해 Optional 객체 생성
//2. null 체크해, 출력하는데 printf를 이용해 출력
//1. OptionalInt optInt1에 0저장
//2. OptionalInt optInt2에 빈 객체 생성
System.out.println(optInt1.isPresent()); // true
System.out.println(optInt2.isPresent()); // false
System.out.println(optInt1.getAsInt()); // 0
//System.out.println(optInt2.getAsInt()); // NoSuchElementException
System.out.println("optInt1 ="+optInt1);
System.out.println("optInt2="+optInt2);
System.out.println("optInt1.equals(optInt2)?"+optInt1.equals(optInt2));
//1. Optional<String> opt에 null저장
//2. Optional<String> opt2에 빈 객체 생성
System.out.println("opt ="+opt);
System.out.println("opt2="+opt2);
System.out.println("opt.equals(opt2)?"+opt.equals(opt2)); // true
//optStrToInt 변환 예외처리 작성을 위한 객체 생성
//1. Optional 123 문자열 생성해 Int형으로 변환하는데, 기본값 0 설정 후 result3에 저장
//2. Optional 빈 문자열 생성해 Int형으로 변환하는데, 기본값 0 설정 후 result4에 저장
System.out.println("result3="+result3);
System.out.println("result4="+result4);
}
//optStrToInt 변환 예외처리하는 static 메서드
//1. try 정상 : Optional<String> 객체인 optStr을 int형으로 변환해, 반환
//2. catch 예외 : 기본값 반환
}
Optional<String> optStr = Optional.of("abcde");
Optional<Integer> optInt = optStr.map(String::length);
int result1 = Optional.of("123")
.filter(x->x.length() >0)
.map(Integer::parseInt).get();
int result2 = Optional.of("")
.filter(x->x.length() >0)
.map(Integer::parseInt).orElse(-1);
Optional.of("456").map(Integer::parseInt)
.ifPresent(x->System.out.printf("result3=%d%n",x));
OptionalInt optInt1 = OptionalInt.of(0); // 0을 저장
OptionalInt optInt2 = OptionalInt.empty(); // 빈 객체를 생성
Optional<String> opt = Optional.ofNullable(null); // null을 저장
Optional<String> opt2 = Optional.empty(); // 빈 객체를 생성
int result3 = optStrToInt(Optional.of("123"), 0);
int result4 = optStrToInt(Optional.of(""), 0);
static int optStrToInt(Optional<String> optStr, int defaultValue) {
try {
return optStr.map(Integer::parseInt).get();
} catch (Exception e){
return defaultValue;
}
}
반응형
'Java > Java 알고리즘 2' 카테고리의 다른 글
[Java 알고리즘] (5) 스트림 생성과 중간연산 (0) | 2022.10.10 |
---|---|
[Java 알고리즘] (2) 해시, BFS/DFS, Stack, DP (0) | 2022.10.09 |
[Java 알고리즘] (1) 그리디, 정렬, 이분탐색, 시뮬레이션 ## (0) | 2022.10.09 |