You will be fine

<이펙티브 자바> 7. 람다와 스트림

by BFine
반응형

www.yes24.com/Product/Goods/65551284

 

이펙티브 자바 Effective Java 3/E

자바 플랫폼 모범 사례 완벽 가이드 - Java 7, 8, 9 대응자바 6 출시 직후 출간된 『이펙티브 자바 2판』 이후로 자바는 커다란 변화를 겪었다. 그래서 졸트상에 빛나는 이 책도 자바 언어와 라이브

www.yes24.com

42. 익명클래스 보다는 람다를 사용하자

  • 익명클래스 방식

    • 코드가 너무 길어서 함수형 프로그래밍에는 부적합!
  • 람다 방식

    • 컴파일러가 대신 문맥을 살펴 타입을 추론 → 웬만하면 모든 매개변수 타입은 생략하는 것이 좋다
  • 자바 8 List의 sort

      words.sort(comparingInt(String::length))
    
       default void sort(Comparator<? super E> c) {
              Object[] a = this.toArray();
              Arrays.sort(a, (Comparator) c);
              ListIterator<E> i = this.listIterator();
              for (Object e : a) {
                  i.next();
                  i.set((E) e);
              }
          }
  • 람다는 이름없고 문서화도 못하기 대문에 코드 자체로 동작이 설명되지 않거나 코드 줄수가 많아질때는 쓰지말자

    • 길어야 3줄일때 사용하자
  • 추상 클래스의 인스턴스를 만들때는 익명클래스를 사용해야 한다

  • 람다는 자신을 참조 할 수 없다 → this는 바깥 인스턴스를 가르킴

43. 람다보다는 메서드 참조를 사용하자

  • :: 연산자를 사용하면 해당 클래스의 static 메서드를 참조 할 수 있다.
  • 참조 유형 4가지 차이가 뭔지 잘모르겠음

44. 표준 함수형 인터페이스를 사용하자

  • 예로 LinkedHashMap의 removeEldestEntry 가장 오래된 녀석을 제거
  • 필요한 용도에 맞는게 있다면 구현하지말고 표준 함수형 인터페이스 메서드를 활용하자
  • 직접만든 함수형 인터페이스는 @FunctionalInterface 를 사용하자

45. 스트림은 주의해서 사용하자

  • 스트림은 데이터 원소의 유무한 시퀀스를 뜻한다
  • 스트림 파이프라인은 이 원소들로 수행하는 연산 단계를 표현하는 것
  • 파이프라인은 소스 스트림에서 시작해 종단 연산으로 끝남
    • 각 중간 연산은 스트림을 어떠한 방식으로 변환한다
  • 스트림 API는 파이프라인 하나를 구성하는 모든 호출을 연결하여 하나의 표현식으로 완성
  • 스트림 처리 어려운것
    • 파이프라인을 통과할때 각단계에서 값 들에 동시 접근이 어렵다

46. 스트림에서는 부작용 없는 함수를 사용하자

  • 아래 코드는 스트림 코드를 가장한 반복적 코드이다

      Map<String,Long> freq = new HashMap<>();
      words.forEach(word -> {freq.merge(word.toLowerCase(),1L,Long::sum)})
    • 모든작업이 종단 연산에서 일어나고 외부상태(freq)를 수정하는 람다를 실행 (결국 람다에서는 상태수정만 발생)
    • forEach 연산은 스트림 계산 결과를 보고할때 이외에 사용하지말자
  • Collectors

    • 생성하는 객체는 일반적으로 컬렉션(toList, toSet, toCollection)
    • toMap
    • groupBy
    • joining

47. 리턴 타입으로는 스트림보다는 컬렉션이 낫다

  • 스트림은 반복을 지원하지 않는다
    • 반복과 스트림을 알맞게 조합해야 좋은 코드가 나온다
    • Stream이 Iterable을 확장하지 않아서 for-each로 스트림을 반복할 수 없다

48. 스트림 병렬화는 주의해서 적용해라

  • 병렬 프로그래밍

    • 안전성과 응답 가능 상태를 유지해햐함
  • 메르센 소수 찍기

      public static void main(String[] args){
        primes().map(p->TWO.pow(p.intValueExact()).subtract(ONE)) // int형태로 추출
                .filter(mer->mer.isProbablePrime(50))
                .limit(20)
                .forEach(System.out::println)
      }
      Stream<BigInteger> primes(){
        return Stream.iterate(TWO,BigInteger::nextProbablePrime);
      }
    • 위를 parallel로 호출할 경우 아무것도 출력 못하면서 CPU는 90프로를 잡아먹는 상태가 계속된다
      • 스트림 라이브러리가 병렬화 하는 방법을 찾지 못함
      • Stream.iterate거나 중간 연산에 limit를 쓰면 병렬로 성능 개선을 기대 할 수 없다
  • ArrayList, HashMap, HashSet, ConcurrentHashMap, 배열, int&long 범위 일때 병렬 효과가 가장 좋다

    • 참조 지역성이 뛰어난 특징 -> 메모리에 연속해서 저장되어 있음
    • 참조 지역성이 낮을 경우 스레드는 데이터가 주메모리에서 캐시 메모리로 전송 되어 오기를 기다리며 긴 시간을 보낸다
  • 종단 연산 중 가장 병렬 수행에 좋은 것은 reduce 이다. (가변 reduce는 좋지 않다)

  • 병렬을 사용하여 출력할때 순서대로 출력하고 싶다면 forEachOredered 를 사용하자

  • 스트림을 잘못 병렬화 하면 오동작 + 성능 저하가 발생

반응형

블로그의 정보

57개월 BackEnd

BFine

활동하기