JAVA/JAVA의 정석

java - Optional<T>

crone 2021. 7. 22. 16:53

T 타입 객체의 래퍼클래스 - Optional<T>

public final class Optional<T> {
    private final T value;
}

 

Optional<T>객체를 생성하는 다양한 방법
String str = "abc";
Optional<String> optVal = Optional.of(str); (of는 static 메서드)
Optional <String>optVal = Optional.of("abc");
Optional <String> optVal = Optional.of(null); //NUllpointerException 발생
Optional<String> optVal = Optional.ofNullable(null); //OK null을 저장할 수 있는 메서드

null 대신 빈 Optional<T> 객체를 사용하자
Optional<String> optVal = null; //널로 초기화. 바람직 하지 않음
Optional<String> optVal = Optional.<String>empty(); ( <String>은 생략 가능하다) // 빈 객체로 초기화

 

Optional<T> 객체의 값 가져오기

Optional<String> optVal = Optional.ofo("abc");
String str1 = optVal.get(); //optVal에 저장된 값을 반환. null이면 예외발생
String str2 = optVal.orElse(""); // optVal에 저장된 값이 null일 때는 ""를 반환
String str3 = optVal.orElseGet(String::new) // 람다식 사용가능() -> new String();
String str5 = optval.orElseThrow(() -> new String());
String str4 = optval.orElseThrow(NullPointerException::new) // 널이면 예외발생 : 예외종류를 규정가능하다.

isPresent() - Optional객체의 값이 null이면 false, 아니면 true를 반환
if(Optional.ofNullable(Str).isPresent()) {
    System.out.println(str);
}
========
Optional.ofNullable(str).ifPresent(System.out::println) // 널이 아닐때만 작업 수행, 널이면 아무 일도 안함
========


OptionaInt, OptionaLong, OptionalDouble 
기본형 값을 감싸는 래퍼 클래스 :: 성능을 위해서
public final class OptionalInt {
    private final boolean isPresent; // 값이 저장되어 있으면 true
    private final int value; //int 타입의 변수
}

값을 가져올 때는 getAsInt();


빈 Optional 객체와의 비교
OptionalInt opt = OptionalInt.of(0);
OptionalInt opt2 = OptionalInt.empty();

System.out.println(opt.isPresent()) // true
System.out.println(opt2.isPresent()) // false
System.out.println(opt.equals(opt2)); // false

 

 

스트림의 최종연산 - forEach()
void forEach(Consumer<? super T> action) // 병렬스트림인 경우 순서가 보장되지 않음
void forEachOrdered(Consumer<? super T> action) //병렬스트림이 경우에도 순서가 보장됨
병렬로 처리할때는 여러스레드가 나눠 처리하기 때문에 순서를 보장하지 않는다.
순서를 보장하지 않는 forEach가 속도가 빠르다


스트림의 최종연산 - 조건검사
boolean allMatch(Predicate<? super T> predicate) // 모든 요소가 조건을 만족시키면true
boolean anyMatch(Predicate <? super T>predicate) //한 요소라도 조건을 만족시키면 true
boolean noneMatch(Predicate <? super T>predicate) // 모든 요소가 조건을 만족시키지 않으면 true

boolean hasFailedStu = stuStream.anyMatch(s ->s.getTotalScore() <= 100); //낙제자가 있는지?

조건에 일치하는 요소 찾기 - findFirst(), findAny() //결과가 null 일수 있으니 Optional
optional<T> findFirst() // 첫 번째 요소를 반환. 순차 스트림에 사용
Optional<T findAny() // 아무거나 하나륿 ㅏㄴ환. 병렬 스트림에 사용 

Optional<Student> result = stuStream.filter(s -> s.getTotalScore() <= 100).findFirst();
Optional<Student> result = parallelStream.filter(s -> getTotalScore() <= 100).findAny()

스프림의 최종연산 - reduce()
스트림의 요소를 하나씩 줄여가며 누적연산 수행 - reduce();

Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumnulator)
identity : 초기값
accumulator : 이전 연산결과와 스트림의 요소에 수행할 연산

int count = intStream.reduce(0, (a,b) -> a + 1) // count()
int sum = intStream.reduce(0, (a, b) -> a + b) // sum()
int max = intStream.reduce(integer.MIN_VALUE, (a, b) -> a > b ? a : b) // max()
int min = intStream.reduce(Integer.MAX_VALUE, (a, b) -> a > b ? a : b) //min()

collect() 와 Collectors
collect()는 Collector를 매개변수로 하는 스트림의 최종연산
Object collect(Collector collector) // Collector를 구현한 클래스의 객체를 매개변수로
Object collect(Supplier supplier, BiConsumner accumnulaotr, BiConsumer cobiner) // 잘 안쓰임

Collector는 수집(collect)에 필요한 메서드를 정의해 놓은 인터페이스
public interface Collector<T, A, R> // T(요소)를 A에 누적한 다음, 결과를 R로 변환해서 반환
{
Supplier<A> supplier(); //Stringbuilder:new // 누적할 곳
BiConsumer<A, T> accumnulator();          //()sb, s) -> sb.append(s)
BinaryOperator<A> combiner();  /             // (sb1, sb2) -> ab1.append(sb2) // 결합방법(병렬) 각각스레드작업을 합치는 것
Function<A, R> finisher();                         // sb -> sb.toString()           //최종변환 R 
Set<Characteristics> characteristics();            // 컬렉터의 특성이 담긴 set 반환

Collectors 클래스는 다양한 기능의 컬렉터(Collector를 구현한 클래스)를 제공
변환 - mapping(), toList(), toMap(), toCoollection(), ....
통계 - counting(), summingInt(), averagingInt(), maxBy(), minBy(), summerizingInt(). ....
문자열 결합 - joining()
리듀싱 - reducing()
그룹화와 분할 - groupingBy(), partitioningBy(), collectionAndThen()

스트림을 컬렉션, 배열로 변환
스트림을 컬렉션으로 변환 - toList(), toSet(), toMap(), toCollection()
List<String> names = stuStream.map(Student::getName).collect(Collectors.toList()) // Stream<Student> ->  Stream<String> //학생이름이 담긴 list
List<String> names = stuStream.map((s) -> s.getName()).collect(Collectors.toList())
ArrayList<String> list = names.stream().collect(Collectors.toCollection(ArrayList::new));;

Map<String, Perseon> map = personStream.collect(Collectors.toMap(p -> p.getRegId(), p ->p))
                                                                                             주민번호, 객체자신(항등함수)

스트림을 배열로 반환 - toArray()
Student[] stuNames = studentStream.toArray(Student[]:: new)
Object[] stuNames = studentStream.toArray();

스트림의 통계 - counting(), summingInt()
스트림의 통계정보 제공  - counting(), summingInt(), maxBy(), minBy() ....
long count = stuStream.count();
long count = stuStream.collect(counting()) // Collectors.counting()  // 그룹별 카운팅

long totalScore = stuStream.mapToInt(Student::getTotalScore).sum() // IntStream의 sum()
long totalScore = stuStream.collect(summingInt(Student::getTotalScore))

OptionalInt topScore = studentStream.mapToInt(Student::getTotalScore).max() // 전체 요소 중 최댓값
Optional<Student> topStudent = stuStream.max(Comparator.comparingint(Student::getTotalScore))
Optional<Student> topStudent = stuStream.collect(maxBy(Comparator.comparingInt(Student::getTotalScore)))
// 그룹별 최댓값


스트림을 리듀싱 - collectors의 reducing() : 그룹별 리듀싱
스트림을 리듀싱 - reducing()
Collector reducing(BinaryOperator<T> op)
Collector reducing(T identity, Binaryoperator<T> op)
Collector reducing(U identity, Function<T, U> mapper, BinaryOperator<U> op) // map+ reduce

IntStream intStream = new Random().ints(1, 46).distinct().limit(6);

OptionalInt max = intStream.reduce(Integer::max) //전체에 대한 reducing
Optional<Integer> max  = intStream.boxed().collect(reducing(Integer::max)) // collector reducing

long sum = intStream.reduce(0, (a,b) -> a + b);
long sum = intStream.boxed().collect(reducing(0, (a, b) -> a + ab)

int greandTotal = stuStream.map(Student::getTotalScore).reduce(0, Integer::sum)
int grandTotal  = stuStream.collect(reducing(0, Student::getTotalScore, Integer::sum));

문자열 스트림의 요소를 모두 연결 - joining()
String studentName = stuStream.map(Student::getName).collect(joining());
String studentName = stuStream.map(Student::getName).collect(joining(",")); // 구분자
String studentName = stuStream.map(Student::getName).collect(joining(",", "[", "]"));
String studentName = stuStream.collect(joining(",")); //student의 toString()으로 결합