[Routine] 8 주차 시작!
![[Routine] 8 주차 시작!](/assets/img/daily/routine/2023/2023-03-12/2023-03-12-myroutine-8th.png)
“2023년 3월 06일 부터 3월 12일 까지의 나의 루틴.”
#목차
2023-03-06
- 오늘은 워니 님의 인강을 들으면서 출근하였다.
- 조만간 이력서를 업데이트해야겠다는 생각이 너무 많이 들게 되었다.
스트림 요소 처리
리소스로부터 스트림 얻기
BaseStream
에는 모든 스트림에서사용할 수 있는 공통 메서드들이 저의되어 있다.
리턴 타입 | 메서드(매개변수) | 소스 |
---|---|---|
Stream<T> | java.util.Collection.stream() java.util.Collection.parallelStream() | List 컬렉션Set 컬렉션 |
Stream<T> IntStream LongStream DoubleStream | Arrays.stream(T[]) , Stream.of(T[]) Arrays.stream(int[]) , IntStream.of(int[]) Arrays.stream(long[]) , LongStream.of(long[]) Arrays.stream(double[]) , DoubleStream.of(double[]) | 배열 |
IntStream | IntStream.range(int, int) IntStream.rangeClosed(int, int) | int 범위 |
LongStream | LongStream.range(long, long) LongStream.rangeClosed(long, long) | long 범위 |
Stream<Path> | Files.list(Path) | 디렉토리 |
Stream<String> | Files.lines(Path, Charset) | 텍스트 파일 |
DoubleStream IntStream LongStream | Random.double(...) Random.ints() Random.longs() | 랜덤 수 |
컬렉션으로부터 스트림 얻기
java.util.Collection
인터페이스는 스트림과parallelStream()
메서드를 가지고 있기 때문에 자식 인터페이스인List
와Set
인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있다. Continue with Get Stream from Collection Commit
배열로부터 스트림 얻기
java.util.Arrays
클래스를 이용하면 다양한 종류의 배열로부터 스트림을 얻을 수 있다. Continue with Get Stream from Arrays Commit
숫자 범위로부터 스트림 얻기
IntStream
또는LongStream
의 정적 메서드인range()
와rangeClose()
메서드를 이용하면 특정 범위의 정수 스트림을 얻을 수 있다.- 첫 번째 매개값은 시작 수이고 두 번째 매개값은 끝 수인데, 끝 수를 포함하지 않으면
range()
, 포함하면rangeClosed()
를 사용한다.
Continue with Get Stream from Range of Numbers Commit
파일로부터 스트림 얻기
java.nio.file.Files
의Lines()
메서드를 이용하면 텍스트 파일의 행 단위 스트림을 얻을 수 있다.- 이는 텍스트 파일에서 한 행씩 읽고 처리할 때 유용하게 사용 할 수 있다.
# file: "data.txt"
{"pno":1, "name":"상품1", "company":"멋진 회사", "price":2340}
{"pno":2, "name":"상품2", "company":"멋진 회사", "price":392}
{"pno":3, "name":"상품3", "company":"멋진 회사", "price":4309}
{"pno":4, "name":"상품4", "company":"멋진 회사", "price":568}
{"pno":5, "name":"상품5", "company":"멋진 회사", "price":4901}
Continue with Get Stream from Files Commit
- 오늘 퇴근은 워니 님의 인강을 들으면서 퇴근 하였다.
- 이번 주에 있을 스터디 발표자료를 얼른 준비해야겠다!
2023-03-07
- 오늘도 어김없이 워니 님의 인강을 들으면서 출근하였다. 역시 나 혼자 생각해서 이력서를 작성하는 것 보다 인사 담당자나 혹은 해당 직무에서 오랫동안 일했던 사람들에게 피드백을 받는 것이 중요하구나 라는 생각을 했다.
- 출근 후 이것이 자바다 한 강의만 듣고 얼른 스터디 자료 준비를 해야겠다~
스트림 요소 처리
요소 걸러내기(필터링)
- 필터링은 요소를 걸러내는 중간 처리 기능이다.
리턴 타입 | 메서드(매개변수) | 설명 |
---|---|---|
Stream IntStream LongStream DoubleStream | distinct() | -중복 제거 |
filter(Predicate<T>) filter(IntPredicate) filter(LongPredicate) filter(DoublePredicate) | -조건 필터링 -매개 타입은 요소 타입에 따른 함수형 인터페이스이므로 람다식으로 작성 가능 |
distinct()
메서드는 요소의 중복을 제거한다.- 객체 스트림(
Stream
)일 경우,equals()
메서드의 리턴값이true
이면 동일한 요소로 판단한다. IntStream
,LongStream
,DoubleStream
은 같은 값일 경우 중복을 제거한다.
filter()
메서드는 매개값으로 주어진Predicate
가true
를 리턴하는 요소만 필터링한다.
인터페이스 | 추상메서드 | 설명 |
---|---|---|
Predicate<T> | boolean test(T t) | 객체 T`를 조사 | |
IntPredicate | boolean test(int value) | int` 값을 조사 | |
LongPredicate | boolean test(Long value) | long` 값을 조사 | |
DoublePredicate | boolean test(Double value) | double` 값을 조사 |
- 모든
Predicate
는 매개값을 조사한 후boolean
을 리턴하는test()
메서드를 가지고 있다. Predicate<T>
의 람다식 표현T -> { ... return true } 또는 T -> true // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
Continue with Filter Stream Commit
- 오늘 퇴근도 어김없이 워니 님의 인강을 들으면서 퇴근하였다.
- 이번 주 목요일날 스터디가 있어 스터디 자료를 얼른 준비 해야겠다.
2023-03-08
- 오늘도 어김없이 워니 님의 인강을 듣고 출근하였다.
- 인강을 다 들어서 얼른 나의 이력서에 반영해봐야겠다.
스트림 요소 처리
요소 변환(매핑)
- 매핑
mapping
은 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능이다. - 매핑 메서드는
mapXXX()
,asDoubleStream()
,asLongStream()
,boxed()
,flatMapXxx()
등이 있다.
요소를 다른 요소로 변환
mapXXX()
메서드는 요소를 다른 요소로 변환한 새로운 스트림을 리턴한다.mapXXX()
메서드의 종류
리턴 타입 | 메서드(매개변수) | 요소 -> 번환 요소 |
---|---|---|
Stream<R> | map(Function<T, R>) | T -> R |
IntStream<R> LongStream<R> DoubleStream<R> | mapToInt(ToIntFunction<T>) mapToLong(ToLongFunction<T>) mapToDouble(ToDoubleFunction<T>) | T -> int T -> long T -> double |
Stream<U> | mapToObj(IntFunction<U>) mapToObj(LongFunction<U>) mapToObj(DoubleFunction<U>) | int -> U long -> U double -> U |
DoubleStream DoubleStream IntStream LongStream | mapToDouble(IntToDoubleFunction) mapToDouble(LongToDoubleFunction) mapToInt(DoubleToIntFunction) mapToLong(DoubleToLongFunction) | int -> double long -> double double -> int double -> long |
- 매개타입인
Function
은 함수형 인터페이스로, 다음과 같은 종류가 있다.
인터페이스 | 추상 메서드 | 매개값 -> 리턴값 |
---|---|---|
Function<T, R> | R apply(T t) | T -> R |
IntFunction<R> | R apply(int value) | int -> R |
LongFunction<R> | R apply(long value) | long -> R |
DoubleFunction<R> | R apply(double value) | double -> R |
ToIntFunction<T> | int applyAsInt(T value) | T -> int |
ToLongFunction<T> | int applyAsLong(T value) | T -> long |
ToDoubleFunction<T> | int applyAsDouble(T value) | T -> double |
IntToLongFunction<T> | long applyAsLong(int value) | int -> long |
IntToDoubleFunction<T> | double applyAsDouble(int value) | int -> double |
LongToIntFunction<T> | int applyAsInt(long value) | long -> int |
LongToDoubleFunction<T> | double applyAsDouble(long value) | long -> double |
DoubleToIntFunction<T> | int applyAsInt(double value) | double -> int |
DoubleToLongFunction<T> | long applyAsLong(double value) | double -> long |
- 모든
Function
은 매개값을 리턴값으로 매핑(변환)하는applyXxx()
메서드를 갖고 있다.
Function<T, R>
을 람다식으로 표현하면 다음과 같다T -> { ... return R; } 또는 T -> R; // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
Continue with Convert Score Stream Commit
- 기본 타입간의 변환이거나 기본 타입 요소를 래퍼
wrapper
객체 요소로 변환하려면 다음과 같은 간편화 메서드를 사용할 수 있다.
리턴 타입 | 메서드(매개변수) | 설명 |
---|---|---|
LongStream | asLongStream() | int -> long |
DoubleStream | asLongStream() | int -> double long -> double |
Stream<Integer> Stram<Long> Stream<Double> | boxed() | int -> Integer long -> Long double -> Double |
Continue with Convert Stream Wrapper Commit
- 오늘은 퇴근을 여자친구와 만나서 저녁을 먹고 퇴근하였다. 그리고 집에 데려다주고 집에 와서 스터디 발표 준비를 하는데 이번 주는 자료조사가 좀 더 길어질 거 같아 기존에 있는 블로그 내용을 토대로 발표할 예정이다.
2023-03-09 스터디 발표
- 늦잠을 자버렸다…😅
- 요새 자료 준비나 공부로 인해 몸이 많이 피곤에 쌓인 듯하다.
- 그래서 오늘은
e-sports
경기 하이라이트를 보면서 출근하였다.😙
스트림 요소 처리
요소 변환(매핑)
요소를 복수 개의 요소로 변환
flatMapXxx()
메서드는 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림을 리턴한다.
리턴 타입 | 메서드(매개변수) | 요소 -> 변환 요소 |
---|---|---|
Stream<R> | flatMap(Function<T, Stream<R>>) | T -> Stream<R> |
DoubleStream | flatMap(DoubleFunction<DoubleStream>) | double -> DoubleStream |
IntStream | flatMap(IntFunction<IntStream>) | int -> IntStream |
LongStream | flatMap(LongFunction<IntStream>) | long -> LongStream |
LongStream | flatMap(LongFunction<IntStream>) | long -> LongStream |
DoubleStream | flatMapToDouble(Function<T, DoubleStream>) | T -> DoubleStream |
IntStream | flatMapToInt(Function<T, IntStream>) | T -> InputStream |
LongStream | flatMapToLong(Function<T, LongStream>) | T -> LongStream |
Continue with Convert Multiple Elements Commit
스터디 발표
코드는 지우개로 지우게 - 인터페이스
asd - 컬레션 프레임워크
승연씨 - 네트워크 기초
스터디 발표를 하고 느낀점
- 스터디를 준비하는 과정과 발표를 하는 과정에서 느낀 점이 나의 포스팅 실력이 형편없는 듯하다는 것을 많이 느꼈다.
- 조금 더 정확하고 짜임새 있는 글을 작성하고 싶다는 생각을 하게 되었다.
- 원래
osi 7 layer
에서physical layer
를 발표하려고 했는데 생각보다 양이 많고, 확인하고 싶은 것이 생겨 이번에는 기존에 올렸던 [JS] Javascript는 싱글 스레드(Single Threaded)인데 어떻게 병렬처리(다중처리)가 가능할까?를 발표하였는데, 작년에 준비한 블로그 내용이었는데 많이 아쉽다는 생각이 들었다. - 꼭 새로운 글이 아닌 기존 글을 조금 더 다듬어서 좋은 내용의 글을 만들고 싶다는 생각이 들어 양보단 질이 중요하다는 것을 느끼게 해준 스터디였다.
- 당분간 블로그 글에 대해 좀 더 방향성을 생각해 보고 다듬는 기간을 가져야겠다.🧐
2023-03-10
- 오늘은 오랜만에 영한 님의 인강을 들으면서 출근하였다.
스트림 요소 처리
요소 정렬
- 정렬은 요소를
오름차순
또는내림차순
으로 정렬하는 중간 처리 기능이다.
리턴 타입 | 메소드(매개변수) | 설명 |
---|---|---|
Stream<T> | sorted() | Comparable 요소를 정렬한 새로운 스트림 생성 |
Stream<T> | sorted(Comparator<T>) | 요소를 Comparable 에 따라 정렬한 새 스트림 생성 |
DoubleStream | sorted() | double 요소를 올림차순 으로 정렬 |
IntStream | sorted() | int 요소를 올림차순 으로 정렬 |
LongStream | sorted() | long 요소를 올림차순 으로 정렬 |
Comparable 구현 객체의 정렬
- 스트림의 요소가 객체일 경우 객체가
Comparable
을 구현하고 있어야만sorted()
메서드를 사용하여 정렬할 수 있다. - 그렇지 않다면
ClassCastException
이 발생한다.
public class Xxx implements Comparable { ... } | List<Xxx> list = new ArrayList<>(); Stream<Xxx> stream =list.stream(); Stream<Xxx> orderedStream = stream.sorted(); |
- 만약
내림차순
으로 정렬하고 싶다면 다음과 같이Comparator.reverseOrder()
메서드가 리턴하는Comparator
를 매개값으로 제공하면 된다.
public class ComparatorReverseOrder {
Stream<Xxx> reverseOrderStream = stream.sorted(Comparator.reverseOrder());
}
Continue with Comparable 구현 객체의 정렬 Commit
Comparator를 이용한 정렬
- 요소 객체가
Comparable
을 구현하고 있지 않다면, 비교자를 제공하면 요소를 정렬시킬 수 있다. - 비교자는
Comparator
인터페이스를 구현한 객체를 말한다.
sorted((o1, o2) -> { ... })
- 중괄호 안에는
o1
이o2
보다 작으면음수
, 같으면0
, 크면 양수를 리턴하도록 작성하면 된다. o1
와o2
가 정수일 경우에는Integer.compare(o1, o2)
를, 실수일 경우에는Double.compare(o1, o2)
를 호출해서 리턴값을 리턴해도 좋다.
Continue with Comparator를 이용한 정렬 Commit
요소를 하나씩 처리(루핑)
- 루핑
looping
은 스트림에서 요소를 하나씩 반복해서 가져와 처리하는 것을 말한다.
리턴 타입 | 메서드(매개변수) | 설명 |
---|---|---|
Stream<T> IntStream DoubleStream | peek(Consumer<? super T>) peek(IntComsumer action) peek(DoubleConsumer acrion) | T 반복int 반복double 반복 |
void | forEach(Consumer<? super T> action) forEach(IntComsumer action) forEach(DoubleConsumer acrion) | T 반복int 반복double 반복 |
peek()
와forEach()
는 동일하게 요소를 루핑하지만peek()
은 중간 처리 메서드이고,forEach()
메서드는 최종 처리 메서드이다.- 따라서
peek()
는 최송 처리가 뒤에 붙지 않으면 동작하지 않는다.
인터페이스명 | 추상 메서드 | 설명 |
---|---|---|
Consumer<T> | void accept(T t) | 매개값 T 를 받아 소비 |
IntConsumer<T> | void accept(int values) | 매개값 int 를 받아 소비 |
LongConsumer<T> | void accept(long values) | 매개값 long 를 받아 소비 |
DoubleConsumer<T> | void accept(double values) | 매개값 double 를 받아 소비 |
Consumer<? supter T>
를 람다식으로 펴한하면 다음과 같다
T -> { ... }
또는
T -> 실행문; // 하나의 실행문만 있을 경우 중괄호 생략
Continue with 요소를 하나씩 처리(루핑) Commit
요소 조건 만족 여부(매칭)
- 매칭은 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능이다.
리턴 타입 | 메서드(매개변수) | 조사 내용 |
---|---|---|
boolean | allMatch(Predicate<T> predicate) allMatch(IntPredicate<T> predicate) allMatch(LongPredicate<T> predicate) allMatch(DoublePredicate<T> predicate) | 모든 요소가 만족하는지 여부 |
boolean | anyMatch(Predicate<T> predicate) anyMatch(IntPredicate<T> predicate) anyMatch(LongPredicate<T> predicate) anyMatch(DoublePredicate<T> predicate) | 최소한 하나의 요소가 만족하는지 |
boolean | noneMatch(Predicate<T> predicate) noneMatch(IntPredicate<T> predicate) noneMatch(LongPredicate<T> predicate) noneMatch(DoublePredicate<T> predicate) | 모든 요소가 만족하지 않는지 여부 |
allMatch()
,anyMatch()
,noneMatch()
메서드는 매개값으로 주어진Predicate
가 리턴하는 값에 따라true
또는false
를 리턴한다.
Continue with 요소 조건 만족 여부(매칭) Commit
요소 기본 집계
- 집계Aggregate는 최종 처리 기능으로 요소들을 처리해서 카운팅, 합계, 평균값, 최대값, 최소값등과 같이 하나의 값으로 산출하는 것을 말한다.
- 즉, 대량의 데이터를 가공해서 하나의 값으로 축소하는 리덕션Reduction이라고 볼 수 있다.
스트림이 제공하는 기본 집계
- 스트림은 카운팅, 최대, 최소, 평균, 합계 등을 처리하는 메서드를 제공한다.
리턴타입 | 메서드(매개변수) | 설명 |
---|---|---|
long | count() | 요소 개수 |
OptionalXxx | findFirst() | 첫 번째 요소 |
Optional<T> OptionalXXX | max(Comparator<T>) max() | 최대 요소 |
Optional<T> OptionalXXX | min(Comparator<T>) min() | 최소 요소 |
OptionalDouble | average() | 요소 평균 |
int , long , double | sum() | 요소 총합 |
- 집계 메서드가 리턴하는
OptionalXXX
는Optional
,OptionalDouble
,OptionalInt
,OptionalLong
클래스를 말한다. - 이들은 최종값을 저장하는 객체로
get()
,getAsDouble()
,getAsInt()
,getAsLong()
을 호출하면 최종값을 얻을 수 있다.
Continue with 스트림이 제공하는 기본 집계 Commit
- 퇴근 후 밥먹고 씻고 잠깐 쉰다는게 일찍 자버렸다…😭
2023-03-11
스트림 요소 처리
요소 기본 집계
Optional 클래스
Optinal
,OptionalDouble
,OptinalInt
,OptinalLong
클래슨는 단순히 집계값만 저장하는 것이 아니라ㅡ 집계값이 존재하지 않을 경우 디폴트 값을 설정하거나 집계값을 처리하는Consumer
를 등록할 수 있다.
리턴 타입 | 메서드(매개변수) | 설명 |
---|---|---|
boolean | isPresent() | 집계값이 있는지 여부 |
T double int long | orElse(T) orElse(double) orElse(int) orElse(long) | 집계값이 없을 경우 디폴트 값 설정 |
void | ifPresent(Consumer) ifPresent(DoubleConsumer) ifPresent(IntConsumer) ifPresent(LongConsumer) | 집계값이 있을 경우 Consumer 에서 처리 |
- 컬렉션의 요소는 동적으로 추가되는 경우가 많다.
- 만약 컬렉션에 요소가 존재하지 않으면 집계 값을 산출할 수 없으므로
NoSuchElementException
예외가 발생한다. - 하지만 앞의 표에 언급되어 있는 메서드를 이용하면 예외 발생을 막을 수 있다.
1) isPresent() 메서드가 true를 리턴할 때만 집계값을 얻는다
import java.util.OptionalDouble;
public class IsPresentTrue {
public static void main(String[] args) {
OptionalDouble optional = stream.average();
if (optional.isPresent()) {
System.out.println("평균 : " + optional.getAsDouble());
} else {
System.out.println("평균 : 0.0");
}
}
}
2) orElse() 메서드로 집계값이 없을 경우를 대비해서 디폴트 값을 정해놓는다
public class IsPresentTrue {
public static void main(String[] args) {
double avg = stream
.average()
.orElse(0.0);
System.out.println("평균 : " + avg);
}
}
3) ifPresent() 메서드로 집계값이 있을 경우에만 동작하는 Consumer 람다식을 제공한다
public class IsPresentTrue {
public static void main(String[] args) {
stream
.average()
.ifPresent(a -> System.out.println("평균 : " + a));
}
}
Continue with Optional 클래스 Commit
요소 커스텀 집계
- 스트림은 기본 집계 메서드인
sum()
,average()
,count()
,max()
,main()
을 제공하지만, 다양한 집계 결과물을 만들 수 있도록reduce()
메서드도 제공한다.
인터페이스 | 리턴 타입 | 메서드(매개변수) |
---|---|---|
Stream | Optional<T> T | reduxe(BinaryOperator<T> accumulator) reduce(T identity, BinaryOperator<T> accumulator) |
IntStream | OptionalInt int | reduxe(IntBinaryOperator op) reduce(int identity, IntBinaryOperator op) |
LongStream | OptionalLong long | reduxe(LongBinaryOperator op) reduce(long identity, LongBinaryOperator op) |
DoubleStream | OptionalDouble double | reduxe(DoubleBinaryOperator op) reduce(double identity, DoubleBinaryOperator op) |
- 매개값인
BinaryOperator
는 함수형 인터페이스이다. BinaryOperator
는 두 개의 매개값을 받아 하나의 값을 리턴하는apply()
메서드를 가지고 있기 때문에 다음과 같이 람다식을 작성할 수 있다.
(a, b) -> { ... return 값; }
또는
(a, b) -> 값 // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
reduce()
는 스트림에 요소가 없을 경우 예외가 발생하지만,identity
매개값이 주어지면 이 값을default 값
으로 리턴한다.
NoSuchElementException | default 값(identity)인 0 리턴 |
---|---|
int sum = stream .reduce((a, b) -> a + b) .getAsInt(); | int sum = stream.reduce(0, (a, b) -> a + b); |
Continue with 요소 커스텀 집계 Commit
요소 수집
- 스트림은 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메서드인
collect()
를 제공한다. - 이 메서드를 이용하면 필요한 요소만 컬렉션에 담을 수 있고, 요소들을 그룹핑한 후에 집계도 할 수 있다.
필터링한 요소 수집
Stream
의collect(Collector<T, A, R> collector)
메서드는 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고, 이 컬렉션을 리턴한다.- 매개값인
Collector
는 어떤 요소를 어떤 컬렉션에 수집할 것인지를 결정한다.
리턴 타입 | 메서드(매개변수) | 인터페이스 |
---|---|---|
R | collect(Collector<T, A, R> collector | Stream |
- 타입 파라미터의
T
는 요소,A
는 누적기accumulator,R
은 요소가 저장될 컬렉션이다. - 즉,
T
요소를A
누적기가R
에 저장한다는 의미이다.
<div style="width:250px">리턴 타입</div> | <div style="width:250px">메서드</div> | 설명 |
---|---|---|
Collector<T, ?, List<T>> | toList() | T 를 List 에 저장 |
Collector<T, ?, Set<T>> | toSet() | T 를 Set 에 저장 |
Collector<T, ?, Map<K, U>> | toMap( Function<T, K> keyMapper, Function<T, U> valueMapper ) | T 를 K 와 U 로 매핑하여 K 를 키로, U 를 값으로 Map 에 저장 |
- 리턴값인
Collector
를 보면A
(누적기accumulator)가?
로 되어 있는데, 이것은Collector
가List
,Set
,Map
컬렉션에 요소를 저장하는 방법을 알고 있어 별도의 누적기가 필요 없기 때문이다. - 아래 코드는 Student 스트림에서 남학생만 필터링해서 별도의 List로 생성하는 코드
//file: "Student 스트림에서 남학생만 필터링해서 별도의 List로 생성하는 코드.java"
import java.util.Collections;
public class Example {
// Student 스트림에서 남학생만 필터링해서 별도의 List로 생성하는 코드
List<Student> maleList = totalList.stream()
.filter(s -> s.getSex().equals("남")) // 남학생만 필터링
.collect(Collections.toList());
}
//file: "Student 스트림에서 이름을 키로, 점수를 값으로 갖는 Map 컬렉션을 생성하는 코드.java"
import java.util.Map;
import java.util.stream.Collectors;
public class Example {
// Student 스트림에서 이름을 키로, 점수를 값으로 갖는 Map 컬렉션을 생성하는 코드
Map<String, Integer> map = totalList.stream()
.collect(
Collectors.toMap(
s -> s.getName(), // Student 객체에서 키가 될 부분 리턴
s -> s.getScore() // Student 객체에서 값이 될 부분 리턴
)
);
}
Java 16
부터 좀 더 편리하게 요소 스트림에서List
컬렉션을 얻을 수 있다.- 스트림에서 바로
toList()
메서드를 다음과 같이 사용하면 된다.
//file: "Java 16부터 스트림에서 List 컬렉션을 얻는 방법.java"
public class Example {
// Java 16부터 스트림에서 List 컬렉션을 얻는 방법
List<Student> maleList = totalList.stream()
.filter(s -> s.getSex().equals("남"))
.toList(); // <-------------- Java 16부터 스트림에서 List 컬렉션을 쉽게 얻는 방법
}
Continue with 요소 수집 Commit
요소 그룹핑
collect()
메서드는 단순히 요소를 수집하는 기능 이외에 컬렉션의 요소들을 그룹핑해서Map
객체를 생성하는 기능도 제공한다.Collectors.groupingBy()
메서드에서 얻은Collector
를collect()
메서드를 호출할 때 제공한다.
리턴 타입 | 메서드 |
---|---|
Collector<T, ?, Map<k, List<T>>> | groupingBy(Function<T, K> classifier) |
groupingBy()
는Function
을 이용해서T
를K
로 매핑하고,K
를 키로 해List<T>
를 값으로 갖는Map
컬렉션을 생성한다.
//file: "'남', '녀'를 키로 설정하고 List<Student>를 값으로 갖는 Map을 생성하는 코드.java"
import java.util.Map;
import java.util.stream.Collectors;
public class Example {
// '남', '녀'를 키로 설정하고 List<Student>를 값으로 갖는 Map을 생성하는 코드
Map<String, List<Student>> map = totalList.stream()
.collect(
Collectors.groupingBy(s -> s.getSex()) // 그룹핑 키 리턴
);
}
Continue with 요소 그룹핑 return key Commit
Collectors.groupingBy()
메서드는 구룹핑 후 매핑 및 집계(평균, 카운팅, 연결, 퇴대, 최소, 합계)를 수행할 수 있도록 두 번째 매개값인Collector
를 가질 수 있다.- 다음은 두 번째 매개값으로 사용될
Collector
를 얻을 수 있는Collectors
의 정적 메서드들이다.
리턴 타입 | 메서드(매개변수) | 설명 |
---|---|---|
Collector | mapping(Function, Collector) | 매핑 |
Collector | averagingDouble(ToDoubleFunction) | 평균값 |
Collector | couting() | 요소 수 |
Collector | maxBy(Comparator) | 최대 값 |
Collector | minBy(Comparator) | 최소 값 |
Collector | reducing(BynaryOperator<T>) reducing(T identity, BinaryOperator<T>) | 커스텀 집계 값 |
//file: "학생들을 성별로 그풉핑하고 각각의 평균 점수를 구해서 Map으로 얻는 코드.java"
import java.util.Map;
import java.util.stream.Collectors;
public class Example {
Map<String, Double> map = totalList.stream()
.collect(
Collectors.groupingBy(
s -> s.getSex(),
Collectors.averagingDouble(s -> s.getScore)
)
);
}
Continue with 요소 그룹핑 return Map Commit
요소 병렬 처리
- 요소 병럴 처리Parallel Operation란 멀티 코어
CPU
환경에서 전체 요소를 분할해서 각각의 코어가 병렬적으로 처리하는 것을 말한다. - 요소 병렬 처리의 목적은 작업 처리 시간을 줄이는 것에 있다.
- 자바는 요소 병렬 처리를 위해 병렬 스트림을 제공한다.
동시성과 병렬성
- 멀티 스레드는 동시성Concurrency 또는 병렬성Parallelism으로 실행되기 때문에 이를 용어에 대해 정확히 이해하는 것이 좋다.
- 동시성은 멀티 작업을 위해 멀티 스레드가 하나의 코어에서 번갈아 가며 실행하는 것을 말하고, 병렬성은 멀티 작업을 위해 멀티 코어를 각각 이용해서 병렬로 실행하는 것을 말한다.
- 동시성은 한 시점에 하나의 작업만 실행한다.
- 번갈아 작업을 실행하는 것이 워낙 빠르다 보니 동시에 처리되는 것처럼 보일 뿐이다.
- 병렬성은 한 시점에서 여러 개의 작업을 병렬로다 실행하기 때문에 동시성보다 좋은 성능을 낸다.
- 병렬성은 데이터 병렬성Dara parallelism과 작업 병렬성Task parallelism으로 구분할 수 있다.
데이터 병렬성
- 데이터 병렬성은 전체 데이터를 분할해서 서브 데이터셋으로 만들고 이 서브 데이터셋들을 병렬 처리해서 작업을 빨리 끝내는 것을 말한다.
- Java 병렬 스트림은 데이터 병렬성을 구현한 것이다.
작업 병렬성
- 작업 병렬성은 서로 다른 작업을 병렬 처리하는 것을 말한다.
- 작업 병렬성의 대표적인 예는 서버 프로그램이다.
- 서버는 각각의 클라이언트에서 요청한 내용을 개별 스레드에서 병렬로 처리한다.
포크조인 프레임워크
- Java 병렬 스트림은 요소들을 병렬 처리하기 위해 포크조인 프레임워크Forkjoin Framework를 사용한다,
- 프로조인 프레임워크는 포그 단계에서 전체 요소를 서브 요소셋으로 분발하고, 각각의 서브 요소셋을 멀티 코어에서 병렬로 처리한다.
- 조인 단계에서 서브 결과를 결합해서 최종 결과를 만들어낸다.
- 예를들어 쿼드 코어
CPU
에서 병렬 스트림으로 요소들을 처리할 경우 먼저 포크 단계에서 스트림의 전체 요소들을 4개의 서브 요소셋으로 분발한다. - 그리고 각각의 서브 요소셋을 개별 코어에서 처리하고, 조인 단계에서는 3번의 결합 과정을 거쳐 최종 결과를 산출한다.
- 병렬 처리 스트림은 포크 단계에서 요소를 순서대로 분할하지 않는다.
- 이해하기 쉽도록 위 그림에서는 앞에서부터 차례대로 4등분 했지만, 내부적으로 요소들을 나누는 알고리즘이 있기 때문에 개발자는 신경 쓸 필요가 없다.
- 포크조인 프레임워크는 병렬 처리를 위해 스레드풀을 사용한다.
- 각각의 코어에서 서브 요소셋을 처리하는 것은 작업 스레드가 해야 하므로 스레드 관리가 필요하다.
- 포크조인 프레임워크는
ExceutorService
의 구현 객체인ForkJoinPool
을 사용해서 작업 스레드를 관리한다.
병렬 스트림 사용
- Java 병렬 스트림을 이용할 경우에는 백그라운드에서 포크조인 프레임워크가 사용되기 때문에 개발자는 매우 쉽게 병렬 처리를 할 수 있다.
리턴 타입 | 메서드 | 제공 컬렉션 또는 스트림 |
---|---|---|
Stream | parallelStream() | List 또는 Set 컬렉션 |
Stream IntStream LongStream DoubleStream | parallel() | java.util.Stream java.util.IntStream java.util.LongStream java.util.DoubleStream |
parallelStream()
메서드는 컬렉션(List
,Set
)으로부터 병렬 스트림을 바로 리턴한다.parallel()
메서드는 기존 스트림을 병렬 처리 스트림으로 변환한다.- 다음 예제는
1억
개의 점수에 대한 평균을 얻을 때 일반 스트림과 병렬 스트림의 처리 시간을 측정한 것이다. - 실행 결과를 보면 병렬 스트림에서 요소 처리 시간이 더 빠른 것을 볼 수 있다.
- 총 3번의 실행을 해보았는데 대략 2배 이상의 실행 속도 차이를 보인다.
Continue with 병렬 스트림 Commit
병렬 처리 성능
- 스트림 병렬 처리가 스트림 순차 처리보다 항상 실행 성능이 좋다고 판단해서는 안 된다.
- 그전에 먼저 병렬 처리에 영향을 미치는 다음 3가지 요인을 잘 살펴보아야 한다.
요소의 수와 요소당 처리 시간
- 컬렉션에 전체 요소의 수가 적고 요소당 처리 시간이 짧으면 일반 스트림이 병렬 스트림보다 빠를 수 있다.
- 병렬 처리는 포크 및 조인 단계가 있고, 스레드 풀을 생성하는 추가적인 비용이 발생하기 때문이다.
스트림 소스의 종류
ArraysList
와 배열은 인덱스로 요소를 관리하기 때문에 포크 단계에서 요소를 쉽게 분리할 수 있어 병렬 처리 시간이 절약된다.- 반면
HashSet
,TreeSet
은 요소 분리가 쉽지 않고,LinkedList
역시 링크를 따라가야 하므로 요소 분리가 쉽지 않다. - 따라서 이 소스들은 상대적으로 병렬 처리가 늦다.
코어(Core)의 수
CPU
코어의 수가 많으면 많을수록 병렬 스트림의 성능은 좋아진다.- 하지만 코어의 수가 적을 경우에는 일반 스트림이 더 빠를 수 있다.
- 병렬 스트림은 스레드 수가 증가하여 동시성이 많이 일어나므로 오히려 느려진다.
2023-03-12
데이터 입출력
입출력 스트림
- 데이터는 키보드를 통해 입력될 수도 있고, 파일 또는프로그램으로부터 입력될 수도 있다.
- 반대로 데이터는 모니터로 출력될 수도 있고, 파일에 저장되거나 다른 프로그램으로 전송될 수 있다.
- 이것을 총칭해서 데이터 입출력이라고 한다.
- Java는 입력 스트림과 출력 스트림을 통해 데이터를 입출력한다.
- 스트림Stream은 단방향으로 데이터가 흐르는 것을 말하는데, 다음 그림과 같이 데이터는 출발지에서 나와 도착지로 흘러 들어간다.
- 프로그램을 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림이 된다.
- 프로그램이 다른 프로그램과 데이터를 교환하려면 양쪽 모두 입력 스트림과 출력 스트림이 필요하다.
- 어떤 데이터를 입출력하느냐에 따라 스트림은 다음 두 종류로 구분할 수 있다.
바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
문자 스트림 : 문자만 입출력할 때 사용 - Java는 데이터 입출력과 관련된 라이브러리를
java.io
패키지에서 제공하고 있다. java.io
패키지는 바이트 스트림과 문자 스트림을 다음과 같이 이름으로 구분해서 제공한다.
구분 | 바이트 스트림 | 문자 스트림 | ||
---|---|---|---|---|
입력 스트림 | 출력 스트림 | 입력 스트림 | 출력 스트림 | |
최상위 클래스 | InputStream | OutputStream | Reader | Writer |
하위 클래스 (예) | XXXInputStream FileInputStream | XXXOutputStream FileOutputStream | XXXReader FileReader | XXXWriter FileWriter |
- 바이트 입출력 스트림의 최상위 클래스는
InputStream
과OutputStream
이다. - 이 클래스를 상속받는 자식 클래스에는 접미사로
InputStream
또는OutputStream
이 붙는다. - 예를 들어 이미지와 같은 바이너리 파일의 입출력 스트림 클래스는
FileInputStream
과FileOutputStream
이다. - 문자 입출력 스트림의 최상위 클래스는
Reader
와Writer
이다. - 이 클래스를 상속받는 하위 클래스에는 접미사로
Reader
또는Writer
가 붙는다. - 예를 들어 텍스트 파일의 입출력 스트림 클래스는
FileReader
와FileWriter
이다.
바이트 출력 스트림
OutputStream
은 바이트 출력 스트림의 최상위 클래스로 추상 클래스이다.- 모든 바이트 출력 스트림 클래스는 이
OutputStream
클래스를 상속받아서 만들어진다.
OutputStream
클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야 할 메서드가 정의되어있다.
리턴 타입 | 메서드 | 설명 |
---|---|---|
void | write(int b) | 1byte 를 출력 |
void | write(byte[] b) | 매개값으로 주어진 배열 b 의 모든 바이트를 출력 |
void | write(byte[] b, int off, int len) | 매개값으로 주어진 배열 b[off] 부터 len 개의 바이트를 출력 |
void | close() | 출력 스트림을 닫고 사용 메모리 해제 |
1바이트 출력
write(int b)
메서드는 매개값int(4byte)
에서 끝1byte
만 출력한다.- 매개변수가
int
타입이므로4byte
모두를 보내는 것은 아니다.
Continue with 1바이트 출력 Commit
FileOutputStream
생성자는 주어진 파일을 생성할 수 없으면IOException
을 발생시킨다.write()
,flush()
,close()
메서드도IOException
이 발생할 수 있으므로 예외 처리를 해야한다.OutputStream
은 내부에 작은 버퍼buffer를 가지고 있다.write()
메서드가 호출되면 버퍼에 바이트를 우선 저장하고, 버퍼가 차면 순서대로 바이트를 출력한다.flush()
메서드는 내부 버퍼에 잔류하는 모든 바이트를 출력하고 버퍼를 비우는 역할을 한다.- 내부 버퍼를 사용하는 이유는 출력 성능을 향상하기 위해서이다.
- 출력 스트림을 더 이상 사용하지 않을 때에는
close()
메서드를 호출해서 출력 스트림이 사용했던 메모리를 해제하는 것이 좋다.
바이트 배열 출력
- 일반적으로
1byte
를 출력하는 경우는 드물고, 보통 바이트 배열을 통째로 출력하는 경우가 많다. write(byte[] b)
메서드는 매개값으로 주어진 배열의 모든 바이트를 출력한다.
Continue with 바이트 배열 출력 Commit
바이트 입력 스트림
InputStream
은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스이다.- 모든 바이트 입력 스트림은
InputStream
클래스를 상속받아 만들어진다.
InputStream
클래스에는 바이트 입력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
리턴 타입 | 메서드 | 설명 |
---|---|---|
int | read() | 1byte 를 읽은 후 읽은 바이트를 리턴 |
int | read(byte[] b) | 읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴 |
void | close() | 입력 스트림을 닫고 상요 메모리 해제 |
1바이트 읽기
read()
메서드는 입력 스트림으로부터1byte
를 읽고int(4byte)
타입으로 리턴한다.- 따라서 리턴된
4byte
중1byte
에만 데이터가 들어 있다. - 예를 들어 입력 스트림에서 5개의 바이트가 들어온 다면 다음과 같이
read()
메서드로1byte
씩 5번 읽을 수 있다.
- 더이상 입력 스트림으로부터 바이트를 읽을 수 없다면
read()
메서드는-1
을 리턴하는데, 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 한 바이트씩 읽을 수 있다.
import java.io.InputStream;
public class Example {
InputStream is = ...;
while (true) {
int data = is.read(); // 1 바이트를 읽고 리턴
if (data == -1) break; // -1을 리턴했을 경우 while 문 종료
}
}
Continue with 1바이트 읽기 Commit
FileInputStream
생성자는 주어진 파일이 존재하지 않을 경우FileNotFoundException
을 발생시킨다.- 그리고
read()
,close()
메서드에서IOException
이 발생할 수 있으므로 두 가지 예외를 모두 처리 해야한다.
바이트 배열로 읽기
read(byte[] b)
메서드는 입력 스트림으로부터 주어진 배열의 길이만큼 바이트를 읽고 배열에 저장한 다음 읽은 바이트 수를 리턴한다.- 예를 들어 입력 스트림에 5개의 바이트가 들어오면 다음과 같이 길이 3인 배열로 두 번 읽을 수 있다.
read(byte[] b)
역시 입력 스트림으로부터 바이트를 더 이상 읽을 수 없다면-1
을 리턴하는데, 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복해서 읽을 수 있다.
import java.io.InputStream;
public class Example {
InputStream is = ...;
byte[] data = new byte[100];
while (true) {
int num = is.read(data); // 최대 100byte를 읽고, 읽은 바이트는 배열 data 저장, 읽은 수는 리턴
if (num == -1) break; // -1을 리턴하면 while 문 종료
}
}
- 많은 양의 바이트를 읽을 때는
read(byte[] b)
메서드를 사용하는 것이 좋다. - 입력 스트림으로부터 100개의 바이트가 들어온다면
read()
메서드는 100번을 반복해서 읽어야 하지만,read(byte[] b)
메서드는 한 번 읽을 때 배열 길이만큼 읽기 때문에 읽는 횟수가 현저히 줄어든다.
Continue with 1바이트 읽기 Commit
Continue with 파일 복사 Commit
문자 입출력 스트림
- 바이트 입출력 스트림인
InputStream
과OutputStream
에 대응하는 문자 입출력 스트림으로Reader
와Writer
가 있다. - 입출력 되는 단위가 문자인 것을 제외하고는 바이트 입출력 스트림과 사용 방법은 동일하다.
문자 출력
Writer
는 문자 출력 스트림의 최상위 클래스로, 추상 클래스이다.- 모든 문자 출력 스트림 클래스는
Writer
클래스를 상속받아서 만들어진다.
Writer
클래스는 모든 문자 출력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
리턴 타입 | 메서드 | 설명 |
---|---|---|
void | write(int c) | 매개값으로 주어진 한 문자를 출력 |
void | write(char[] cbuf) | 매개값으로 주어진 배열의 모든 문자를 출력 |
void | write(char[] cbuf, int off, int len) | 매개값으로 주어진 배열에서 cbuf[off] 부터 len 까지의 문자를 출력 |
void | write(String str) | 매개값으로 주어진 문자열을 출력 |
void | write(String str, int off, int len) | 매개값으로 주어진 문자열에서 off 순번부터 len 개까지의 문자를 출력 |
void | flush() | 버퍼에 잔류하는 모든 문자를 출력 |
void | close() | 출력 스트림을 닫고 사용 메모리를 해제 |
Writer
는OutputStream
과 사용방법은 동일하지만, 출력 단위가 문자(char)
이다.- 문자열을 출력하는
write(String str)
메서드를 추가로 제공한다.
Continue with 문자 출력 Commit
문자 읽기
Reader
는 문자 입력 스트림의 최상위 클래스고, 추상 클래스이다.- 모든 문자 입력 스트림 클래스는
Reader
클래스를 상속받아서 만들어진다.
Reader
클래스에는 문자 입력 스트림이 기본적으로 가져야 할 메서드가 저으이되어 있다.
리턴 타입 | 메서드 | 설명 |
---|---|---|
int | read() | 1개의 문자를 읽고 리턴 |
int | read(char[] cbuf) | 읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 문자 수를 리턴 |
void | close() | 입력 스트림을 닫고, 사용 메모리 해제 |
Reader
는InputStream
과 사용 방법은 동일하지만, 출력 단위가 문자(char)
이다.
Continue with 문자 읽기 Commit
보조 스트림
- 보조 스트림이란 다른 스츠림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림을 말한다.
- 보조 스트림은 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다.
- 입출력 스트림에 보조 스트림을 연결하려면 보조 스트림을 생성할 때 생성자 매개값으로 입출력 스트림을 제공하면 된다.
- 보조스트림 변수 = new 보조스트림(입출력스트림);
- 예를 들어 바이트 입력 스트림인
FileInputStream
에InputStreamReader
보조 스ㅡ림을 연결하는 코드는 다음과 같다.
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Example {
InputStream is = new FileInputStream("...");
InputStreamReader reader = new InputStreamReader(is);
}
- 보조 스트림은 또 다른 보조 스트림과 연결되어 스트림 체인으로 구성할 수 있다.
- 예를 들어 문자 변환 보조 스트림은
InputStreamReader
에BufferedReader
보조 스트림을 연결하는 코드는 다음과 같다.
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Example {
InputStream is = new FileInputStream("...");
InputStreamReader reader = new InputStreamReader(is);
BufferedInputStream br = new BufferedInputStream(reader);
}
보조 스트림 | 기능 |
---|---|
InputStreamReader | 바이트 스트림을 문자 스트림으로 변환 |
BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter | 입출력 성능 향상 |
DataInputStream DataOutputStream | 기본 타입 데이터 입출력 |
PrintStream PrintWriter | 줄바꿈 처리 및 형식화된 문자열 출력 |
ObjectInputStream ObjectOutputStream | 객체 입출력 |
문자 변환 스트림
- 바이트 스트림(
InputStream
,OutputStream
)에서 입출력할 데이터가 문자라면 문자 스트림(Reader
와Writer
)로 변환해서 사용하는 것이 좋다. - 그 이유는 문자로 바로 입출력하는 편리함이 있고, 문자셋의 종류를 지정할 수 있기 때문이다.
InputStream을 Reader로 변환
InputStream
을Reader
로 변환하려면InputStreamReader
보조 스트림을 연결하면 된다.
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
public class Example {
InputStream is = new FileInputStream("파일경로.파일확장명");
Reader reader = new InputStreamReader(is);
}
- FileReader의 원리
FileInputStream에 InputStreamReader을 연결하지 않고 FileReader를 직접 생성할 수 있다.
FileReader는 InputStreamReader의 자식 클래스이다.
이것은 FileReader가 내부적으로 FileInputStream에 InputStreamReader 보조 스트림을 연결한 것이라고 볼 수 있다.
OutputStream을 Writer로 변환
OutputStream
을Writer
로 변환하려면OutputStreamWriter
보조 스트림을 연결하면 된다.
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class Example {
OutputStream os = new FileOutputStream("파일경로/파일명.확장자명");
Writer writer = new OutputStreamWriter(os);
}
- FileWriter의 원리
FileOutputStream에 OutputStreamWriter를 연결하지 않고 FileWriter를 직접 생성할 수 있다.
FileWriter는 OutputStreamWriter의 자식 클래스이다.
이것은 FileWriter가 내부적으로 FileOutputStream에 OutputStreamWriter 보조 스트림을 연결한 것이라고 볼 수 있다.
Continue with OutputStream을 Writer로 변환 Commit
Reference
Back to [Routine] 7 주차 시작!
Continue with [Routine] 9 주차 시작!