본문 바로가기

Java

Java 람다와 스트림 -(2)

람다와 스트림



1.스트림

 

1) Optional<T>

 

래퍼 클래스(Wrapper Class)는

8개의 기본 타입에 해당하는 데이터를 객체로 표현하기 위해 포장해주는 클래스

 

Optional<T>는 T타입의 객체를 감싸는 래퍼 클래스이다.

따라서 Optional타입의 객체에는 모든 타입의 객체를 담을 수 있다.

 

최종 연산의 결과를 그냥 반환하는 게 아니라,

Optional 객체에 담아서 반환하면 

그 결과가 null인지  체크하는 if문 없어도 NullPointerException이 발생하지 않는다.

간결하고 편리하다. 



① Optional<T> 객체 생성하기

 

of 또는 ofNullable()을 사용한다.

 

String str  =”abc”;

Optional<String> optVal = Optional.of(str);

Optional<String> optVal = Optional.of(“abc”);

Optional<String> optVal = Optional.of(new String(“abc”);



만약 참조변수 값이 null일 가능성이 있다면 of()대신 ofNullable을 사용해야 한다.

 

Optional<String> optVal = Optional.of(null);                   //NullPointerException발생

Optional<String> optVal = Optional.ofNullable(null);       //Ok

 

만약 Optional<T>타입의 참조변수를 기본값으로 초기화할 때 empty()를 사용한다.

null로 초기화하는 것이 가능하지만 empty()로 초기화하는 것이 바람직하다.

 

Optional<String> optVal = Optional.<String>empty();     //빈 객체로 초기화



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

 

Optional 객체에 저장된 값을 가져올 때 get()을 사용한다

단, 값이 null일 경우를 대비하여 orElse()로 값을 지정할 수 있다.

 

Optional<String> optVal =Optional.of(“abc”);

String str1 = optVal.get();          //optVal에 지정된 값을 반환.null이면 예외 발생

String str2 =optVal.orElse(“”);     //optVal에 저장된 값이 null일 때는, “”를 반환



orElse의 변형으로 null을 대체할 값을 반환하는 람다식을 지정할 수 있다.

orElseGet()과 null일 때 예외를 발생시키는 orElseThrow()가 있다.

 

String str3 = optVal2.orElse(String::new); //() -> new String()과 동일

String str4 = optVal2.orElseThrow(NullPointerException::new); //널이면 예외 발생



isPresent() 는 Optional객체의 값이 null이면 false, 아니면 true를 반환한다

 

ifPresent() (Consumer<T> block)은 값이 있으면 주어진 람다식을 실행하고,

없으면 아무 일도 하지 않는다.



예시)  다음과 같은 조건문이 있다.

 

if(str != null) {System.out.println(str);}

 

isPresent()를 이용해 이렇게 작성할 수 있다.

 

if(Optional.ofNullable(str).isPresent()) {System.out.println(str)}

 

ifPresent()를 통해 보다 간결할 수 있다.

 

Optional.ofNullable(str).ifPresent(System.out::println);

 

참조변수 str이 null이 아니면 값을 출력하고, null이면 아무 일도 일어나지 않는다.



③ OptionalInt, OptionalLong, OptionalDouble

 

IntStream과 같은 기본형 스트림의 최종 연산의 일부는

Optional 대신 OptionalInt, OptionalLong, OptionalDouble을 반환한다.

 

기본형 int의 기본값은 0이므로

아무런 값을 갖지 않는 OptionalInt에 저장된 값은 0일 것이다.

 

OptionalInt opt = OptionalInt.of(0) ;        //OptionalInt에 0을저장

OptionalInt opt2 = OptionalInt.empty();    

 

저장된 값이 없는 것과 0인 것은 isPresent를 통해 구분 가능하다.

 

System.out.println(opt.isPresent());     //true

System.out.println(opt2.isPresent());   //false

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

 

스트림 최종 연산 Optional<T>



2) 스트림의 최종연산

 

스트림의 최종연산은 스트림의 요소를 모두 소모한 결과이다.

이로 인해 최종연산 후 스트림은 닫히며, 더이상 사용될 수 없다.

 

① 스트림의 최종 연산 - 조건검사



boolean allMatch (Predicate < ? super T> predicate> 모든 요소가 일치하면  참

boolean anyMatch (Predicate < ? super T> predicate> 하나의 요소라도 일치하면  참

boolean noneMatch (Predicate < ? super T> predicate> 모든 요소가 불일치하면  참

 

Optional<T> findfirst() 조건에 일치하는 첫번째 요소를 반환

Optional<T> findAny() 조건에 일치하는 요소를 하나 반환(병렬 스트림)

 

cf. findFrist()와 findAny()의 반환타입은 Optional<T>이며,

스트림의 요소가 없을 때는 비어있는 Optional객체를 반환한다



② 스트림의 최종 연산 - reduce()

 

스트림의 요소를 줄여가며 연산을 수행하고 최종 결과 반환

스트림의 최종 연산 - reduce()

 

2-2) 스트림의 최종 연산 - collect

 

collect()가 스트림의 요소를 수집하려면

어떻게 수집할 것인 가에 대한방법이 정의돼야 한다.

이 방법을 정의 한 것이 컬렉터(Collector)이다.



collect() 스트림의 최종 연산. 매개변수로 컬렉터를 필요로한다.

Collector 인터페이스, 컬렉터는 이 인터페이스를 구현해야 한다.

Collectors 클래스,미리 작성된 컬렉터를 제공한다.(컬렉터를 구현한 클래스)

 

collect()의 매개변수 타입이 Collector인데

이는 Collector를 구현한 클래스의 객체여야 한다는 의미이다.

 

그리고 collect()는 이 객체에 구현된 방법대로 스트림 요소를 수집한다. 



① 스트림을 컬렉션으로 변환 - toList(), toSet(), toMap(), toCollction()

② 스트림을 배열로 변환 -toArray()

 

Student[] stuNames = studentStream.toArray(Student[]::new); //ok.

Student[] stuNames = studentStream.toArray(); //에러

Object[] stuNames = studentStream.toArray(); //ok.

 

Student 스트림을 Student배열에 담으려면 매개변수가 있는 toArray()를 써야 한다.

매개변수가 없는 toArray()를 쓴다면 Object배열에 담아야 한다.

 

③ 스트림의 통계 - counting(), summingInt() 

 

collect()를 사용한 통계는 그룹별로 나누어 계산하는 게 가능하다.

그냥 count의 경우 전체로 계산한다.

 

④ 스트림을 리듀싱 - reducing()

 

reduce()와 하는 일은 같다.

reducing은 그룹별 리듀싱이 가능하다.

 

⑤ 스트림을 문자열로 결합 - joining()

 

문자열 스트림의 모든 요소를 하나의 문자열로 연결하여 반환

 

구분자를 지정할 수 있고, 접두사/접미사를 지정할 수도 있다.

스트링의 문자열 요소가 문자열이 아닌 경우 먼저 map()을 이용해 문자열로 변환해야 한다



⑥ 스트림의 그룹화와 분할

 

그룹화 → 스트림의 요소를 특정 기준으로 그룹화

분할 → 스트림의 요소를 두 가지로 분할.

    지정된 조건에 일치하는 그룹, 불일치하는 그룹으로 분할

 

groupBy() → 스트림의 요소를 Function으로

partitioningBy() → 스트림의 요소를 Predicate으로 분류한다



스트림을 두 개의 그룹으로 나눠야 한다면 partitioningBy()이 적합하다.

그리고 그룹화와 분할의 결과는 Map에 담겨서 반환된다.

 

문자열 길이를 더한 결과 출력
문자열 배열의 문자열 중에서 가장 긴 것의 길이를 출력하기
스트림의 그룹화와 분할
스트림의 그룹화와 분할 2
스트림의 그룹화와 분할 3

 

'Java' 카테고리의 다른 글