스트림(Stream)이란?
- filter(중간연산) : predicate를 인자로 받아서 true인 요소만을 반환
스트림 API의 활용 - 필터링/슬라이싱
- distinct(중간 연산) : 유일한 값을 반환한다.
- limit (중간 연산) : 지정된 숫자만큼 반환한다.
=> 처음 3개까지만 뽑아서 새로운 스트림 만들어라.
=> 최종 연산에는 우리가 사용할 데이터 타입으로 리턴해준다.
스트림 API의 활용 - 매핑
map (중간 연산) : 스트림의 T 객체를 U로 변환. 파라미터로 Function<T, U>를 사용.
=> map은 기존의 스트림에서 엘레먼트의 수는 그대로 유지하되 엘레먼트의 성격이 달라짐. 그 전엔 Dish라는 스트림이었는데 map 연산을 거치면 map의 파라미터로 들어오는 함수가 각각의 엘레먼트에 어플라이됨.
=> reduce는 최종 연산인데, int와 같은 하나의 최종적인 값을 만들어낸다. 폴딩이라고도 한다. 인접한 엘레먼트 두개를 특정 로직에서 연산을 수행한다. 200 + 50 = 250이고, 이를 폴딩이라 한다. 이를 250과 또 더함.
스트림 API의 활용 - 최종 연산
reduce [최종연산] : reduce(init, operator) 또는 reduce(operator) 형태로 사용
=> 폴딩이라고도 한다. 결과를 누적시켜나간다.
NullPointException에서 벗어나기
- Null의 가장 큰 문제점은 모든 타입이 Null이 될 수 있다는 것이다.
- 그리고 Null로 한 의도를 알 수 없다는 것.
- 데이터가 없어서 Null로 한건지, 데이터 연산이 안되서 그런건지 모름.
- Null은 굉장히 성가시고 제대로 해결해주지 않으면 프로그래밍 자체가 안정적이지 못하게 됨.
- 자바8에서 Null을 처리하는 좋은 방식이 도입됨.
=> USB의 버전을 확인하고 싶을 때 computer 안의 getSoundcard() 메소드에 getUSB 메소드의 getVersion 메소드를 호출하게 되는데, 이 넷 중 하나라도 Null이 있다면 전체가 오류가 나면서 NullPointException이 발생한다. 코드 자체가 불안해진다.
NullPointException을 예방하기 위해서
=> null 체크 : 이를 예방하기 위해 항상 computer!=null 처럼, null이 아닌 경우에만 수행하는 조건문을 걸어줌. 하지만 코드가 길어지고 보기 좋지 않음.
Optional 사용하기
- Optional은 값이 있거나 또는 없는 경우를 표현하기 위한 클래스
=> NullPointException을 해결하기 위한 새로운 방법. 기존의 타입을 옵셔널로 래핑함.
=> optional은 함수형 프로그램의 일환.
=> flatMap을 통해 null인지 아닌지를 판단하여 null이 아닐때는 version이 정확하게 출력되지만 null일 경우 “unknown”이 출력되게 됨.
=> 옵셔널로 래핑해서 널인지 아닌지를 잘 판단해서 널일경우 출력이 안되지만 널이 아닐 경우 (ifPresent) 제대로 출력하게 됨.
=> 자바를 포함한 모던 프로그래밍언어는 다 optional같은 null처리하는 함수가 포함됨. 옵셔널로 래핑하는게 가독성도 좋고 나중에 유지보수도 쉬워진다.
결과 모으기 - collect() (최종 연산자)
스트림을 이용한 작업을 마치고 결과를 자료구조로 모은다.
- Collectors.toList() - 작업의 결과를 리스트로 모으기
- Collectors.toSet() - 작업의 결과를 집합으로 모으기
실습 코드
package com.acompany.stream;
import org.w3c.dom.ls.LSOutput;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) throws IOException { // 예외는 일단 던져준다.
// Path 클래스를 이용해 파일을 읽어들인다.
Path path = Paths.get("cities.txt");
System.out.println(path.toAbsolutePath());
// Files 클래스로 한줄씩 읽고 스트림으로 생성한다.
Stream<String> stringStream = Files.lines(path);
// forEach를 사용해 스트링 스트림을 각 라인별로 출력해보자.
//stringStream.forEach(System.out::println);
// 매핑으로 가공해서 출력해보자. Map은 A가 들어가서 B가 나온다.
Optional<Integer> integer =
// reduce로 나오는 숫자는 null일수도, 아닐수도 있기 때문에 optional로 체크해줘야 한다.
stringStream.map(l -> Integer.parseInt(l.split(",")[1].trim())) // 띄어쓰기를 기준으로 분리한 것의 2번? 인덱스. 즉, 인구수만 출력된다
// 출력되는 문자는 String이다. 이를 숫자로 다시 바꿔주기 위해 우선 문자 앞 공백을 trim()으로 제거하고 Integer.parseInt로 정수화한다.
.filter(p -> p >= 1_000_000)
// 인구가 100만 이상인것만으로 필터링한다.
//.forEach(System.out::println);
.reduce((a, b) -> a + b);
System.out.println(integer.get());
// 앞서 reduce로 구한 인구 합이 출력된다.
/*
//// 데이터를 의도적으로 Null로 만들어보자 ////
integer = Optional.empty();
System.out.println(integer.get());
// => "No value present" 라는 에러가 나옴. 그래서 옵셔널을 쓰면 nullpointexception을 피할 수 있음.
*/
// 위에처럼 get() 메소드말고 옵셔널에서 데이터를 가져올땐 ifPresent 메소드도 많이 쓴다.
// 만약 데이터가 있으면 출력하라는 뜻.
//integer.ifPresent(System.out::println);
// 데이터가 있으면 원래 데이터를, 없으면 0을 리턴해주세요
int data = integer.orElse(0);
System.out.println(data);
}
}
'Programming > Java' 카테고리의 다른 글
[ JAVA 수업 DAY 01 ] Java 기초 (0) | 2020.04.12 |
---|---|
[Java9 프로그래밍] 17. 입출력 처리하기 (0) | 2020.03.30 |
[Java9 프로그래밍] 15. 스트림 (0) | 2020.03.30 |
[Java9 프로그래밍] 14. 제네릭과 컬렉션 (0) | 2020.03.29 |
[Java9 프로그래밍] 13. 예외 처리 (0) | 2020.03.21 |