[Routine] 8 주차 시작!

[Routine] 8 주차 시작!

2023년 3월 06일 부터 3월 12일 까지의 나의 루틴.

#목차

2023-03-06

2023-03-06

  • 오늘은 워니 님의 인강을 들으면서 출근하였다.
  • 조만간 이력서를 업데이트해야겠다는 생각이 너무 많이 들게 되었다.

스트림 요소 처리

리소스로부터 스트림 얻기

Base Stream

  • 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[])
배열
IntStreamIntStream.range(int, int)
IntStream.rangeClosed(int, int)
int 범위
LongStreamLongStream.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() 메서드를 가지고 있기 때문에 자식 인터페이스인 ListSet 인터페이스를 구현한 모든 컬렉션에서 객체 스트림을 얻을 수 있다. 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.FilesLines() 메서드를 이용하면 텍스트 파일의 행 단위 스트림을 얻을 수 있다.
  • 이는 텍스트 파일에서 한 행씩 읽고 처리할 때 유용하게 사용 할 수 있다.
# 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

2023-03-07

  • 오늘도 어김없이 워니 님의 인강을 들으면서 출근하였다. 역시 나 혼자 생각해서 이력서를 작성하는 것 보다 인사 담당자나 혹은 해당 직무에서 오랫동안 일했던 사람들에게 피드백을 받는 것이 중요하구나 라는 생각을 했다.
  • 출근 후 이것이 자바다 한 강의만 듣고 얼른 스터디 자료 준비를 해야겠다~

스트림 요소 처리

요소 걸러내기(필터링)

  • 필터링은 요소를 걸러내는 중간 처리 기능이다.
리턴 타입메서드(매개변수)설명
Stream
IntStream
LongStream
DoubleStream
distinct()-중복 제거
filter(Predicate<T>)
filter(IntPredicate)
filter(LongPredicate)
filter(DoublePredicate)
-조건 필터링
-매개 타입은 요소 타입에 따른 함수형 인터페이스이므로 람다식으로 작성 가능
  • distinct() 메서드는 요소의 중복을 제거한다.
  • 객체 스트림(Stream)일 경우, equals() 메서드의 리턴값이 true이면 동일한 요소로 판단한다.
  • IntStream, LongStream, DoubleStream은 같은 값일 경우 중복을 제거한다.

Distinct

  • filter() 메서드는 매개값으로 주어진 Predicatetrue를 리턴하는 요소만 필터링한다. filter
인터페이스추상메서드설명
Predicate<T>boolean test(T t) | 객체 T`를 조사 
IntPredicateboolean test(int value) | int` 값을 조사 
LongPredicateboolean test(Long value) | long` 값을 조사 
DoublePredicateboolean test(Double value) | double` 값을 조사 
  • 모든 Predicate는 매개값을 조사한 후 boolean을 리턴하는 test() 메서드를 가지고 있다. Predicate
  • Predicate<T>의 람다식 표현
    T -> { ... return true }
    또는
    T -> true   // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
    

Continue with Filter Stream Commit


  • 오늘 퇴근도 어김없이 워니 님의 인강을 들으면서 퇴근하였다.
  • 이번 주 목요일날 스터디가 있어 스터디 자료를 얼른 준비 해야겠다.

2023-03-08

2023-03-08

  • 오늘도 어김없이 워니 님의 인강을 듣고 출근하였다.
  • 인강을 다 들어서 얼른 나의 이력서에 반영해봐야겠다.

스트림 요소 처리

요소 변환(매핑)

  • 매핑mapping은 스트림의 요소를 다른 요소로 변환하는 중간 처리 기능이다.
  • 매핑 메서드는 mapXXX(), asDoubleStream(), asLongStream(), boxed(), flatMapXxx() 등이 있다.
요소를 다른 요소로 변환
  • mapXXX() 메서드는 요소를 다른 요소로 변환한 새로운 스트림을 리턴한다. Original to New Stream
  • 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() 메서드를 갖고 있다.

Apply Method

  • Function<T, R>을 람다식으로 표현하면 다음과 같다
    T -> { ... return R; }
    또는
    T -> R; // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
    

Continue with Convert Score Stream Commit

  • 기본 타입간의 변환이거나 기본 타입 요소를 래퍼wrapper 객체 요소로 변환하려면 다음과 같은 간편화 메서드를 사용할 수 있다.
리턴 타입메서드(매개변수)설명
LongStreamasLongStream()int -> long
DoubleStreamasLongStream()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 스터디 발표

2023-03-09

  • 늦잠을 자버렸다…😅
  • 요새 자료 준비나 공부로 인해 몸이 많이 피곤에 쌓인 듯하다.
  • 그래서 오늘은 e-sports 경기 하이라이트를 보면서 출근하였다.😙

스트림 요소 처리

요소 변환(매핑)

요소를 복수 개의 요소로 변환
  • flatMapXxx() 메서드는 하나의 요소를 복수 개의 요소들로 변환한 새로운 스트림을 리턴한다.

Convert Multiple Elements

리턴 타입메서드(매개변수)요소 -> 변환 요소
Stream<R>flatMap(Function<T, Stream<R>>)T -> Stream<R>
DoubleStreamflatMap(DoubleFunction<DoubleStream>)double -> DoubleStream
IntStreamflatMap(IntFunction<IntStream>)int -> IntStream
LongStreamflatMap(LongFunction<IntStream>)long -> LongStream
LongStreamflatMap(LongFunction<IntStream>)long -> LongStream
DoubleStreamflatMapToDouble(Function<T, DoubleStream>)T -> DoubleStream
IntStreamflatMapToInt(Function<T, IntStream>)T -> InputStream
LongStreamflatMapToLong(Function<T, LongStream>)T -> LongStream

Continue with Convert Multiple Elements Commit


스터디 발표

  1. 코드는 지우개로 지우게 - 인터페이스

  2. asd - 컬레션 프레임워크

  3. 승연씨 - 네트워크 기초

스터디 발표를 하고 느낀점

  • 스터디를 준비하는 과정과 발표를 하는 과정에서 느낀 점이 나의 포스팅 실력이 형편없는 듯하다는 것을 많이 느꼈다.
  • 조금 더 정확하고 짜임새 있는 글을 작성하고 싶다는 생각을 하게 되었다.
  • 원래 osi 7 layer에서 physical layer를 발표하려고 했는데 생각보다 양이 많고, 확인하고 싶은 것이 생겨 이번에는 기존에 올렸던 [JS] Javascript는 싱글 스레드(Single Threaded)인데 어떻게 병렬처리(다중처리)가 가능할까?를 발표하였는데, 작년에 준비한 블로그 내용이었는데 많이 아쉽다는 생각이 들었다.
  • 꼭 새로운 글이 아닌 기존 글을 조금 더 다듬어서 좋은 내용의 글을 만들고 싶다는 생각이 들어 양보단 질이 중요하다는 것을 느끼게 해준 스터디였다.
  • 당분간 블로그 글에 대해 좀 더 방향성을 생각해 보고 다듬는 기간을 가져야겠다.🧐

2023-03-10

2023-03-10

  • 오늘은 오랜만에 영한 님의 인강을 들으면서 출근하였다.

스트림 요소 처리

요소 정렬

  • 정렬은 요소를 오름차순 또는 내림차순으로 정렬하는 중간 처리 기능이다.
리턴 타입메소드(매개변수)설명
Stream<T>sorted()Comparable 요소를 정렬한 새로운 스트림 생성
Stream<T>sorted(Comparator<T>)요소를 Comparable에 따라 정렬한 새 스트림 생성
DoubleStreamsorted()double 요소를 올림차순으로 정렬
IntStreamsorted()int 요소를 올림차순으로 정렬
LongStreamsorted()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) -> { ... })
  • 중괄호 안에는 o1o2보다 작으면 음수, 같으면 0, 크면 양수를 리턴하도록 작성하면 된다.
  • o1o2가 정수일 경우에는 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반복
voidforEach(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

요소 조건 만족 여부(매칭)

  • 매칭은 요소들이 특정 조건에 만족하는지 여부를 조사하는 최종 처리 기능이다.
리턴 타입메서드(매개변수)조사 내용
booleanallMatch(Predicate<T> predicate)allMatch(IntPredicate<T> predicate)
allMatch(LongPredicate<T> predicate)
allMatch(DoublePredicate<T> predicate)
모든 요소가 만족하는지 여부
booleananyMatch(Predicate<T> predicate)
anyMatch(IntPredicate<T> predicate)
anyMatch(LongPredicate<T> predicate)
anyMatch(DoublePredicate<T> predicate)
최소한 하나의 요소가 만족하는지
booleannoneMatch(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이라고 볼 수 있다.
스트림이 제공하는 기본 집계
  • 스트림은 카운팅, 최대, 최소, 평균, 합계 등을 처리하는 메서드를 제공한다.
리턴타입메서드(매개변수)설명
longcount()요소 개수
OptionalXxxfindFirst()첫 번째 요소
Optional<T>
OptionalXXX
max(Comparator<T>)
max()
최대 요소
Optional<T>
OptionalXXX
min(Comparator<T>)
min()
최소 요소
OptionalDoubleaverage()요소 평균
int, long, doublesum()요소 총합
  • 집계 메서드가 리턴하는 OptionalXXXOptional, OptionalDouble, OptionalInt, OptionalLong 클래스를 말한다.
  • 이들은 최종값을 저장하는 객체로 get(), getAsDouble(), getAsInt(), getAsLong()을 호출하면 최종값을 얻을 수 있다.

Continue with 스트림이 제공하는 기본 집계 Commit


  • 퇴근 후 밥먹고 씻고 잠깐 쉰다는게 일찍 자버렸다…😭

2023-03-11


스트림 요소 처리

요소 기본 집계

Optional 클래스
  • Optinal, OptionalDouble, OptinalInt, OptinalLong 클래슨는 단순히 집계값만 저장하는 것이 아니라ㅡ 집계값이 존재하지 않을 경우 디폴트 값을 설정하거나 집계값을 처리하는 Consumer를 등록할 수 있다.
리턴 타입메서드(매개변수)설명
booleanisPresent()집계값이 있는지 여부
T
double
int
long
orElse(T)
orElse(double)
orElse(int)
orElse(long)
집계값이 없을 경우 디폴트 값 설정
voidifPresent(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() 메서드도 제공한다.
인터페이스리턴 타입메서드(매개변수)
StreamOptional<T>
T
reduxe(BinaryOperator<T> accumulator)
reduce(T identity, BinaryOperator<T> accumulator)
IntStreamOptionalInt
int
reduxe(IntBinaryOperator op)
reduce(int identity, IntBinaryOperator op)
LongStreamOptionalLong
long
reduxe(LongBinaryOperator op)
reduce(long identity, LongBinaryOperator op)
DoubleStreamOptionalDouble
double
reduxe(DoubleBinaryOperator op)
reduce(double identity, DoubleBinaryOperator op)
  • 매개값인 BinaryOperator는 함수형 인터페이스이다.
  • BinaryOperator는 두 개의 매개값을 받아 하나의 값을 리턴하는 apply() 메서드를 가지고 있기 때문에 다음과 같이 람다식을 작성할 수 있다.
(a, b) -> { ... return 값; }
또는
(a, b) -> 값 // return 문만 있을 경우 중괄호와 return 키워드 생략 가능
  • reduce()는 스트림에 요소가 없을 경우 예외가 발생하지만, identity 매개값이 주어지면 이 값을 default 값으로 리턴한다.
NoSuchElementExceptiondefault 값(identity)인 0 리턴
int sum = stream
   .reduce((a, b) -> a + b)
   .getAsInt();
int sum = stream.reduce(0, (a, b) -> a + b);

Continue with 요소 커스텀 집계 Commit

요소 수집

  • 스트림은 요소들을 필터링 또는 매핑한 후 요소들을 수집하는 최종 처리 메서드인 collect()를 제공한다.
  • 이 메서드를 이용하면 필요한 요소만 컬렉션에 담을 수 있고, 요소들을 그룹핑한 후에 집계도 할 수 있다.
필터링한 요소 수집
  • Streamcollect(Collector<T, A, R> collector) 메서드는 필터링 또는 매핑된 요소들을 새로운 컬렉션에 수집하고, 이 컬렉션을 리턴한다.
  • 매개값인 Collector는 어떤 요소를 어떤 컬렉션에 수집할 것인지를 결정한다.
리턴 타입메서드(매개변수)인터페이스
Rcollect(Collector<T, A, R> collectorStream
  • 타입 파라미터의 T는 요소, A는 누적기accumulator, R은 요소가 저장될 컬렉션이다.
  • 즉, T 요소를 A 누적기가 R에 저장한다는 의미이다.
<div style="width:250px">리턴 타입</div><div style="width:250px">메서드</div>설명
Collector<T, ?, List<T>>toList()TList에 저장
Collector<T, ?, Set<T>>toSet()TSet에 저장
Collector<T, ?, Map<K, U>>toMap(
   Function<T, K> keyMapper,
   Function<T, U> valueMapper
)
TKU로 매핑하여 K를 키로, U를 값으로 Map에 저장
  • 리턴값인 Collector를 보면 A(누적기accumulator)가 ?로 되어 있는데, 이것은 CollectorList, 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() 메서드에서 얻은 Collectorcollect() 메서드를 호출할 때 제공한다.
리턴 타입메서드
Collector<T, ?, Map<k, List<T>>>groupingBy(Function<T, K> classifier)
  • groupingBy()Function을 이용해서 TK로 매핑하고, 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의 정적 메서드들이다.
리턴 타입메서드(매개변수)설명
Collectormapping(Function, Collector)매핑
CollectoraveragingDouble(ToDoubleFunction)평균값
Collectorcouting()요소 수
CollectormaxBy(Comparator)최대 값
CollectorminBy(Comparator)최소 값
Collectorreducing(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으로 실행되기 때문에 이를 용어에 대해 정확히 이해하는 것이 좋다.
  • 동시성은 멀티 작업을 위해 멀티 스레드가 하나의 코어에서 번갈아 가며 실행하는 것을 말하고, 병렬성은 멀티 작업을 위해 멀티 코어를 각각 이용해서 병렬로 실행하는 것을 말한다.

Concurrency Parallelism

  • 동시성은 한 시점에 하나의 작업만 실행한다.
  • 번갈아 작업을 실행하는 것이 워낙 빠르다 보니 동시에 처리되는 것처럼 보일 뿐이다.
  • 병렬성은 한 시점에서 여러 개의 작업을 병렬로다 실행하기 때문에 동시성보다 좋은 성능을 낸다.
  • 병렬성은 데이터 병렬성Dara parallelism과 작업 병렬성Task parallelism으로 구분할 수 있다.
데이터 병렬성
  • 데이터 병렬성은 전체 데이터를 분할해서 서브 데이터셋으로 만들고 이 서브 데이터셋들을 병렬 처리해서 작업을 빨리 끝내는 것을 말한다.
  • Java 병렬 스트림은 데이터 병렬성을 구현한 것이다.
작업 병렬성
  • 작업 병렬성은 서로 다른 작업을 병렬 처리하는 것을 말한다.
  • 작업 병렬성의 대표적인 예는 서버 프로그램이다.
  • 서버는 각각의 클라이언트에서 요청한 내용을 개별 스레드에서 병렬로 처리한다.
포크조인 프레임워크
  • Java 병렬 스트림은 요소들을 병렬 처리하기 위해 포크조인 프레임워크Forkjoin Framework를 사용한다,
  • 프로조인 프레임워크는 포그 단계에서 전체 요소를 서브 요소셋으로 분발하고, 각각의 서브 요소셋을 멀티 코어에서 병렬로 처리한다.
  • 조인 단계에서 서브 결과를 결합해서 최종 결과를 만들어낸다.
  • 예를들어 쿼드 코어 CPU에서 병렬 스트림으로 요소들을 처리할 경우 먼저 포크 단계에서 스트림의 전체 요소들을 4개의 서브 요소셋으로 분발한다.
  • 그리고 각각의 서브 요소셋을 개별 코어에서 처리하고, 조인 단계에서는 3번의 결합 과정을 거쳐 최종 결과를 산출한다.

Forkjoin Framwork

  • 병렬 처리 스트림은 포크 단계에서 요소를 순서대로 분할하지 않는다.
  • 이해하기 쉽도록 위 그림에서는 앞에서부터 차례대로 4등분 했지만, 내부적으로 요소들을 나누는 알고리즘이 있기 때문에 개발자는 신경 쓸 필요가 없다.
  • 포크조인 프레임워크는 병렬 처리를 위해 스레드풀을 사용한다.
  • 각각의 코어에서 서브 요소셋을 처리하는 것은 작업 스레드가 해야 하므로 스레드 관리가 필요하다.
  • 포크조인 프레임워크는 ExceutorService의 구현 객체인 ForkJoinPool을 사용해서 작업 스레드를 관리한다.

Thread Pool

병렬 스트림 사용
  • Java 병렬 스트림을 이용할 경우에는 백그라운드에서 포크조인 프레임워크가 사용되기 때문에 개발자는 매우 쉽게 병렬 처리를 할 수 있다.
리턴 타입메서드제공 컬렉션 또는 스트림
StreamparallelStream()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은 단방향으로 데이터가 흐르는 것을 말하는데, 다음 그림과 같이 데이터는 출발지에서 나와 도착지로 흘러 들어간다.

Input Output Stream

  • 프로그램을 기준으로 데이터가 들어오면 입력 스트림, 데이터가 나가면 출력 스트림이 된다.
  • 프로그램이 다른 프로그램과 데이터를 교환하려면 양쪽 모두 입력 스트림과 출력 스트림이 필요하다.

Program Input Output Stream

  • 어떤 데이터를 입출력하느냐에 따라 스트림은 다음 두 종류로 구분할 수 있다.

    바이트 스트림 : 그림, 멀티미디어, 문자 등 모든 종류의 데이터를 입출력할 때 사용
    문자 스트림 : 문자만 입출력할 때 사용

  • Java는 데이터 입출력과 관련된 라이브러리를 java.io 패키지에서 제공하고 있다.
  • java.io 패키지는 바이트 스트림과 문자 스트림을 다음과 같이 이름으로 구분해서 제공한다.
구분바이트 스트림문자 스트림
입력 스트림출력 스트림입력 스트림출력 스트림
최상위 클래스InputStreamOutputStreamReaderWriter
하위 클래스
(예)
XXXInputStream
FileInputStream
XXXOutputStream
FileOutputStream
XXXReader
FileReader
XXXWriter
FileWriter
  • 바이트 입출력 스트림의 최상위 클래스는 InputStreamOutputStream이다.
  • 이 클래스를 상속받는 자식 클래스에는 접미사로 InputStream 또는 OutputStream이 붙는다.
  • 예를 들어 이미지와 같은 바이너리 파일의 입출력 스트림 클래스는 FileInputStreamFileOutputStream이다.
  • 문자 입출력 스트림의 최상위 클래스는 ReaderWriter이다.
  • 이 클래스를 상속받는 하위 클래스에는 접미사로 Reader 또는 Writer가 붙는다.
  • 예를 들어 텍스트 파일의 입출력 스트림 클래스는 FileReaderFileWriter이다.

File Input Output Stream

바이트 출력 스트림

  • OutputStream은 바이트 출력 스트림의 최상위 클래스로 추상 클래스이다.
  • 모든 바이트 출력 스트림 클래스는 이 OutputStream 클래스를 상속받아서 만들어진다.

Output Node

  • OutputStream 클래스에는 모든 바이트 출력 스트림이 기본적으로 가져야 할 메서드가 정의되어있다.
리턴 타입메서드설명
voidwrite(int b)1byte를 출력
voidwrite(byte[] b)매개값으로 주어진 배열 b의 모든 바이트를 출력
voidwrite(byte[] b, int off, int len)매개값으로 주어진 배열 b[off]부터 len개의 바이트를 출력
voidclose()출력 스트림을 닫고 사용 메모리 해제
1바이트 출력
  • write(int b) 메서드는 매개값 int(4byte)에서 끝 1byte만 출력한다.
  • 매개변수가 int 타입이므로 4byte 모두를 보내는 것은 아니다.

Output Byte

Continue with 1바이트 출력 Commit

  • FileOutputStream 생성자는 주어진 파일을 생성할 수 없으면 IOException을 발생시킨다.
  • write(), flush(), close() 메서드도 IOException이 발생할 수 있으므로 예외 처리를 해야한다.
  • OutputStream은 내부에 작은 버퍼buffer를 가지고 있다.
  • write() 메서드가 호출되면 버퍼에 바이트를 우선 저장하고, 버퍼가 차면 순서대로 바이트를 출력한다.
  • flush() 메서드는 내부 버퍼에 잔류하는 모든 바이트를 출력하고 버퍼를 비우는 역할을 한다.
  • 내부 버퍼를 사용하는 이유는 출력 성능을 향상하기 위해서이다.
  • 출력 스트림을 더 이상 사용하지 않을 때에는 close() 메서드를 호출해서 출력 스트림이 사용했던 메모리를 해제하는 것이 좋다.
바이트 배열 출력
  • 일반적으로 1byte를 출력하는 경우는 드물고, 보통 바이트 배열을 통째로 출력하는 경우가 많다.
  • write(byte[] b) 메서드는 매개값으로 주어진 배열의 모든 바이트를 출력한다.

Output Byte Array

Continue with 바이트 배열 출력 Commit

바이트 입력 스트림

  • InputStream은 바이트 입력 스트림의 최상위 클래스로, 추상 클래스이다.
  • 모든 바이트 입력 스트림은 InputStream 클래스를 상속받아 만들어진다.

Input Node

  • InputStream 클래스에는 바이트 입력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
리턴 타입메서드설명
intread()1byte를 읽은 후 읽은 바이트를 리턴
intread(byte[] b)읽은 바이트를 매개값으로 주어진 배열에 저장 후 읽은 바이트 수를 리턴
voidclose()입력 스트림을 닫고 상요 메모리 해제
1바이트 읽기
  • read() 메서드는 입력 스트림으로부터 1byte를 읽고 int(4byte) 타입으로 리턴한다.
  • 따라서 리턴된 4byte1byte에만 데이터가 들어 있다.
  • 예를 들어 입력 스트림에서 5개의 바이트가 들어온 다면 다음과 같이 read() 메서드로 1byte씩 5번 읽을 수 있다.

Input Read

  • 더이상 입력 스트림으로부터 바이트를 읽을 수 없다면 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인 배열로 두 번 읽을 수 있다.

Input Read Array

  • 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

문자 입출력 스트림

  • 바이트 입출력 스트림인 InputStreamOutputStream에 대응하는 문자 입출력 스트림으로 ReaderWriter가 있다.
  • 입출력 되는 단위가 문자인 것을 제외하고는 바이트 입출력 스트림과 사용 방법은 동일하다.
문자 출력
  • Writer는 문자 출력 스트림의 최상위 클래스로, 추상 클래스이다.
  • 모든 문자 출력 스트림 클래스는 Writer 클래스를 상속받아서 만들어진다.

Writer

  • Writer 클래스는 모든 문자 출력 스트림이 기본적으로 가져야 할 메서드가 정의되어 있다.
리턴 타입메서드설명
voidwrite(int c)매개값으로 주어진 한 문자를 출력
voidwrite(char[] cbuf)매개값으로 주어진 배열의 모든 문자를 출력
voidwrite(char[] cbuf, int off, int len)매개값으로 주어진 배열에서 cbuf[off]부터 len까지의 문자를 출력
voidwrite(String str)매개값으로 주어진 문자열을 출력
voidwrite(String str, int off, int len)매개값으로 주어진 문자열에서 off 순번부터 len개까지의 문자를 출력
voidflush()버퍼에 잔류하는 모든 문자를 출력
voidclose()출력 스트림을 닫고 사용 메모리를 해제
  • WriterOutputStream과 사용방법은 동일하지만, 출력 단위가 문자(char)이다.
  • 문자열을 출력하는 write(String str) 메서드를 추가로 제공한다.

Continue with 문자 출력 Commit

문자 읽기
  • Reader는 문자 입력 스트림의 최상위 클래스고, 추상 클래스이다.
  • 모든 문자 입력 스트림 클래스는 Reader 클래스를 상속받아서 만들어진다.

Reader

  • Reader 클래스에는 문자 입력 스트림이 기본적으로 가져야 할 메서드가 저으이되어 있다.
리턴 타입메서드설명
intread()1개의 문자를 읽고 리턴
intread(char[] cbuf)읽은 문자들을 매개값으로 주어진 문자 배열에 저장하고 읽은 문자 수를 리턴
voidclose()입력 스트림을 닫고, 사용 메모리 해제
  • ReaderInputStream과 사용 방법은 동일하지만, 출력 단위가 문자(char)이다.

Continue with 문자 읽기 Commit

보조 스트림

  • 보조 스트림이란 다른 스츠림과 연결되어 여러 가지 편리한 기능을 제공해주는 스트림을 말한다.
  • 보조 스트림은 자체적으로 입출력을 수행할 수 없기 때문에 입출력 소스로부터 직접 생성된 입출력 스트림에 연결해서 사용해야 한다.

Secondary Stream

  • 입출력 스트림에 보조 스트림을 연결하려면 보조 스트림을 생성할 때 생성자 매개값으로 입출력 스트림을 제공하면 된다.
  • 보조스트림 변수 = new 보조스트림(입출력스트림);
  • 예를 들어 바이트 입력 스트림인 FileInputStreamInputStreamReader 보조 스ㅡ림을 연결하는 코드는 다음과 같다.
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Example {
    InputStream is = new FileInputStream("...");
    InputStreamReader reader = new InputStreamReader(is);
}
  • 보조 스트림은 또 다른 보조 스트림과 연결되어 스트림 체인으로 구성할 수 있다.

Double Secondary Stream

  • 예를 들어 문자 변환 보조 스트림은 InputStreamReaderBufferedReader 보조 스트림을 연결하는 코드는 다음과 같다.
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)에서 입출력할 데이터가 문자라면 문자 스트림(ReaderWriter)로 변환해서 사용하는 것이 좋다.
  • 그 이유는 문자로 바로 입출력하는 편리함이 있고, 문자셋의 종류를 지정할 수 있기 때문이다.
InputStream을 Reader로 변환
  • InputStreamReader로 변환하려면 InputStreamReader 보조 스트림을 연결하면 된다.

Input Reader Stream

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로 변환
  • OutputStreamWriter로 변환하려면 OutputStreamWriter 보조 스트림을 연결하면 된다.

Output Stream Writer

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 주차 시작!