Java 8 (2) - 기본 메소드(defalt method) / Stream

김정욱·2021년 6월 12일
0

Java

목록 보기
10/13
post-thumbnail

인터페이스의 변화

  • Java 8에 오면서 인터페이스 구성에 변화가 생김
  • 정적(Static) 메소드를 가질 수 있게됨
    • 사실 정적 메소드인스턴스와 상관이 없어서 기술적으로 제한될 이유는 없음
    • Java 8 부터는 유연한 인터페이스를 위해 정적 메소드를 가질 수 있게 됨
  • 기본 메소드(Default Method) 추가
    • 인터페이스기본 메소드추가해서 필요한 하위 클래스만 구현해서 사용가능해짐 --> 유연성
    • 인터페이스에 새로운 기능을 추가할 때 유용

기본 메소드(default method)

[ 설명 ]

  • Java 8 에 도입
  • 인터페이스메소드 선언이 뿐만 아니라, 구현체를 제공할 수 있는 방법
  • 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가하기 좋음 --> 유연성
  • 본인이 원하는 하위 인터페이스, 클래스에만 제공할 수 있음

[ 특징 ]

  • 구현체가 모르게 구현된 기능이라서 리스크가 존재
    • 컴파일 에러는 발생하지 않지만, 구현체에 따라 런타임 에러가 발생할 수 있다
    • @implSpec 라는 자바독 태그를 사용해서 문서화 작업을 해줘야 함
      --> 해당 메서드하위 클래스 사이관계를 설명해서, 상속 혹은 호출 관련 정보문서화 해주어야 함
  • Object가 제공하는 기능(equals, hasCode)는 기본 메소드로 제공할 수 없다
    • 구현체가 재정의 해야함
  • 인터페이스를 상속받는 인터페이스에서 기본 메서드(default method)를 다시 추상메소드로 변경 가능
  • 인터페이스 구현체재정의 할 수 있음

[ 주의할 점 ]

  • 디폴트 메서드기존의 메서드충돌하는 문제가 발생할 수 있다
    • 여러 인터페이스디폴트 메서드 간 충돌
      --> 인터페이스를 구현한 클래스에서 디폴트 메서드오버라이딩 하면 해결
    • 디폴트 메서드조상 클래스의 메서드 간의 충돌
      --> 조상 클래스 메서드우선적으로 적용
      --> 이것도 위 해결 처럼 직접 오버라이딩을 해서 해결할 수 있음

[ Java 8 API의 변화 ]

  • 기본 메소드가 등장하고 우리가 기존에 사용하던 객체들의 API가 추가
  • Iterable
    • forEach(Consumer)
    • spliterator()
      • split 기능을 가진 iterator
      • .tryAdvance()를 통해 순회
      • .trySplit()을 통해 균등하게 분할
  • Collection
    • stream() / parallelStream() : stream 단순 처리 / stream을 병렬 처리
    • removeIf(Predicate) : true인 것을 제외하고 반환
    • spliterator()
  • Comparator
    • 기본 메서드
      • reversed()
      • thenComparaing() : 추가적으로 더 비교할 때 사용
    • 정적 메서드
      • reverseOrder() / naturalOrder()
      • nullsFirst() / nullLast()
      • comparaing()

Stream

ref : https://dororongju.tistory.com/137

[ 설명 ]

Stream

  • 저장된 데이터의 흐름
  • Stream API를 통해 유연하게 데이터를 처리할 수 있음
  • 데이터를 담고 있는 저장소(컬렉션)가 아님
  • 원본 데이터변경되지 않는다
  • 스트림으로 처리하는 데이터는 오직 한 번만 처리
  • 무제한일 수도 있다
    • 계속 들어오는 실시간 데이터를 처리할 수도 있음 (Short Circuit 메소드로 제한 가능)
  • 손쉽게 병렬처리 가능
    • .parallelStream()을 사용해서 손쉬운 병렬처리 가능
  • 중개 오퍼레이션(intermediate operation)은 근본적으로 Lazy 하게 동작
    • 모든 데이터하나의 오퍼레이션 단위수행하는 것이 아님
    • 하나의 데이터모든 오퍼레이션의 순서에 맞게 수행
    • 결과적으로 불필요한 연산을 하지 않는 전략
    • 중개 오퍼레이션만 있으면 동작을 수행하지 X --> 종료 오퍼레이션필요
  • Eager
  • Lazy

스트림 파이프 라인(Stream Pipe Line)

  • 스트림에 존재하는 오퍼레이션의 집합
  • 0 또는 다수의 중개(intermediate) 오퍼레이션과 한개의 종료(terminal) 오퍼레이션으로 구성
  • 반드시 종료(terminal) 오퍼레이션을 실행할 때에만 처리

중개(intermediate) 오퍼레이션

  • Stream반환 O
  • 종류
    • Stateless
      • 대부분의 중개 오퍼레이션이 속함
      • 이전 소스 데이터를 사용은 하되, 연산 중다시 이전 값을 참조하지는 않는 연산
      • filter() / map() / limit() / skip()
    • Stateful
      • 연산 중이전 값을 참조해야 하는 오퍼레이션
      • distinct() / sorted()

종료(terminal) 오퍼레이션

  • Stream반환 X
  • collect() / allMatch() / count() / forEach() / min() / max()

[ Stream API ]

  • filter(Predicate) : true에 해당하는 요소들만 선택해서 거르는 용도
  • map(Function) : 값을 변경해서 반환하는 용도
  • flatMap(Function)
    • 스트림의 형태배열과 같을 때, 모든 원소단일 원소 스트림으로 반환
    • 2개의 ArrayList --> 1개의 ArraList
  • 생성 관련
    • generate(Supplier)
    • Iterate(T seed, UnayOperator)
  • 제한 관련
    • limit(long)
    • skip(long)
  • count() : 개수 세는 용도
  • 특정 조건 만족
    • anyMatch() : 조건에 맞는게 하나라도 있으면 true
    • allMatch() : 조건에 모두 맞으면 true
    • nonMatch() : 조건에 맞는게 없으면 true
  • 스트림을 하나의 데이터로 만들기
    • reduce(identity, BiFunction)
    • collect()
    • sum()
    • max()

[ Stream API 예시 ]

병렬 처리 비교

  • 일반 stream()을 사용하면 하나의 쓰레드에서 수행됨
  • parallelStream()을 사용하면 여러개의 쓰레드병렬 처리로 수행됨
  • 반드시 병렬처리가 효율적인 것은 아님 --> 쓰레드 생성, 문맥교환 등의 cost 발생

다양한 예시(1)

  • filter() / map()중개형 오퍼레이션
  • forEach() / collect()종료형 오퍼레이션
  • flatMap을 통해 2개의 ArrayList하나flat화

다양한 예시(2)

  • skip() / limit() 을 통해 제한
  • anyMatch() 를 통해 하나라도 있으면 true 반환
  • 메소드 레퍼런스를 통해 간결하게 표현 가능!
    • OnlineClass::getTitle
    • System.out::println
profile
Developer & PhotoGrapher

0개의 댓글