가자공부하러!

모던자바인액션(CH8) - 스트림과 람다 활용(1) 본문

공부/Java

모던자바인액션(CH8) - 스트림과 람다 활용(1)

오피스엑소더스 2020. 6. 7. 22:19

목차

요약 및 결론
책 내용
컬렉션 리터럴
for-each 반복문은 내부적으로 Iterator 객체를 사용한다


요약 및 결론

만나서 반갑다 comparingByValue


책 내용

  1. 컬렉션 팩토리

    • 쉽게 컬렉션 객체를 만드는 새로운 방법들
      • .asList()
    • UnsupportedOperationException
      • asList는 innerClass로 구현한 ArrayList를 반환하기 때문에 .add()등 사용 불가
      • Intellij에서 코드 빨간줄은 안나오는데 Exception은 발생함
      • 참고 : https://donnaknew.tistory.com/22
    • 리스트 팩토리 메소드
      • List.of(...)
      • add불가, null요소 불가
    • 집합 팩토리 메소드
      • Set.of(...)
      • 중복 요소 불가, add불가
    • 맵 팩토리 메소드
      • Map.of(K, V, K, V, ...)
      • 요소 10개 이상은 Map.ofEntries(entry(K,V), entry(K,V), ...)
  2. 리스트와 집합 처리

    • removeIf

      • predicate를 만족하는 요소 제거

        transactions.removeIf(transaction -> 
        Character.isDigit(transaction.getReferenceCode().charAt(0)));
    • replaceAll

      • UnaryOperation(단항연산) 함수를 이용해 요소 변경

        List<String> codes = Arrays.asList("a12", "c14", "b13");
        codes.replaceAll(code -> Character.toUpperCase(code.charAt(0)) + code.substring(1));
        log.debug("codes : {}", codes);
  3. 맵 처리

    • 자바8에서 Map 인터페이스에 추가된 디폴트 메소드 소개

    • forEach

      Map<String, Integer> ageOfFriends= new HashMap();
      ageOfFriends.put("A", 1);
      ageOfFriends.put("B", 2);
      for(Map.Entry<String, Integer> entry : ageOfFriends.entrySet()) {
        log.debug("entry : {}", entry);
      }
      ageOfFriends.forEach((k, v) -> {
        log.debug("k : {}, v : {}", k, v);
      });
    • 정렬

      //학원공부할때 Map 정렬이 아주 힘들었던 경험이 있었는데 다신 없을듯 해서 기쁘다
      //Entry.comparingByKey()도 있다.
      Map<String, Integer> ageOfFriends= new HashMap();
      ageOfFriends.put("A", 1);
      ageOfFriends.put("B", 2);
      ageOfFriends.entrySet()
          .stream()
          .sorted(Entry.comparingByValue())
          .forEachOrdered((entry) -> log.debug("entry : {}", entry));
    • getOrDefault

      //getOrDefault(K, V); Map에 K가 없으면 V 밸류 반환. 당연히 밸류타입 맞춰줘야함
      ageOfFriends.getOrDefault("C", 3);
    • 계산 패턴

      • computeIfAbsent : 제공된 키에 해당하는 값이 없거나 null이면 키를 이용해 새 값을 계산하고 맵에 추가

      • computeIfPresent : 제공된 키가 존재하면 새 값을 계산하고 맵에 추가

      • compute : 제공된 키로 새 값을계산하고 맵에 저장(뭔가 복잡할때 쓰는건가 put이랑 차이를 모르겟음)

        Map<String, Integer> ageOfFriends= new HashMap();
        ageOfFriends.put("A", 1);
        ageOfFriends.put("B", 2);
        log.debug("C : {}", ageOfFriends.get("C"));    //C : null
        ageOfFriends.computeIfAbsent("C", k -> 5 + 5);
        log.debug("C : {}", ageOfFriends.get("C"));    //C : 10
    • 삭제 패턴

      //remove(K, V) K, V 모두 일치하는 요소만 제거
      Map<String, Integer> ageOfFriends= new HashMap();
      ageOfFriends.put("A", 1);
      ageOfFriends.put("B", 2);
      ageOfFriends.remove("B", 1);
      log.debug("B : {}", ageOfFriends.get("B"));    //B : 2
      ageOfFriends.remove("B", 2);
      log.debug("B : {}", ageOfFriends.get("B"));    //B : null
    • 교체 패턴

      • replaceAll : Bifunction을 적용한 결과로 각 항목의 값을 교체

      • replace : 키가 존재하면 맵의 값 변경

        Map<String, Integer> ageOfFriends= new HashMap();
        ageOfFriends.put("A", 1);
        ageOfFriends.put("B", 2);
        ageOfFriends.replace("B", 3);
        log.debug("map : {}", ageOfFriends);    //map : {A=1, B=3}
        ageOfFriends.replaceAll((k, v) -> v + 1);
        log.debug("map : {}", ageOfFriends);    //map : {A=2, B=4}
    • 병합

      • merge

        Map<String, Integer> myFriends= new HashMap();
        myFriends.put("A", 1);
        myFriends.put("B", 2);
        Map<String, Integer> hisFriends= new HashMap();
        hisFriends.put("A", 40);
        //키 충돌 해결
        myFriends.forEach((k, v) -> hisFriends.merge(k, v, (age1, age2) -> age1 + age2));
        log.debug("map : {}", myFriends); //map : {A=1, B=2}
        log.debug("map : {}", hisFriends);  //map : {A=41, B=2}
  4. 개선된 ConcurrentHashMap

    • 특징

      • 동시성 친화적인 HashMap의 버전
        • 내부 자료구조의 특정 부분만 잠궈 동시에 추가, 갱신 작업을 허용
    • 리듀스와 검색

      • 지원하는 연산 형태
        • K, V로 연산(forEach, reduce, search)
        • K로 연산(forEachKey, reduceKeys,searchKeys)
        • V로 연산(forEachValue, reduceValues, searchValues)
        • Map.Entry 객체로 연산(forEachEntry, reduceEntries, searchEntries)
      • 계산이 진행되는 동안 바뀔 수 있는 객체, 값, 순서 등에 의존하지 않아야 한다.
        • 상태를 잠그지 않고 연산을 수행하기 때문
      • 병렬성 기준값(threshold)을 지정해야 함
        • 맵의 크기가 주어진 기준값 보다 작으면 순차적으로 연산
        • 기준값을 1로 지정하면 공통 스레드 풀을이용해 병렬성을 극대화함
        • Long.MAX_VALUE를 기준값으로 설정하면 한 개의 스레드로 연산을 실행
    • 개수

      • 계수는 오타인듯

      • 맵의 매핑 개수를 반환하는 mappingCount메소드 제공

        • 매핑의 개수가 int의 범위를 넘어서는 상황을 대처할 수 있는 장점

          ConcurrentHashMap<String, Integer> myFriends= new ConcurrentHashMap();
          myFriends.put("A", 1);
          myFriends.put("B", 2);
          log.debug("size : {}", myFriends.size()); // size : 2
          log.debug("mappingCount : {}", myFriends.mappingCount()); //mappingCount : 2
    • 집합뷰

      • ConcurrentHashMap을 집합 뷰로 반환하는 keySet 메소드 제공

      • 맵을 바꾸면 집합도 바뀌고 집합을 바꾸면 맵도 바뀐다

        //신기하다
        ConcurrentHashMap<String, Integer> myFriends= new ConcurrentHashMap();
        myFriends.put("A", 1);
        myFriends.put("B", 2);
        KeySetView<String, Integer> keySet = myFriends.keySet();
        keySet.remove("B");
        log.debug("map : {}", myFriends); // map : {A=1}
        log.debug("keySet : {}", keySet); // keySet : [A]
        myFriends.put("B", 3);
        log.debug("map : {}", myFriends); // map : {A=1, B=3}
        log.debug("keySet : {}", keySet); // keySet : [A, B]

컬렉션 리터럴

//파이썬에서
//출처 : https://wikidocs.net/20562
[ ... ]로 감싸져 있으면 list자료형
( ... )로 감싸져 있으면 tuple자료형
{ 키:값, ... }로 감싸져 있으면 dictionary자료형
{ ... }로 감싸져 있으면 set자료형

for-each 반복문은 내부적으로 Iterator 객체를 사용한다

그렇다

Comments