ch1. 자바 8, 9, 10, 11

1. 역사의 흐름은 무엇인가?

자바 역사를 통틀어 가장 큰 변화가 자바 8에서 일어났다.

자바 8은 어떤 변화를 불러왔는가?

Collections.sort(inventory, new Comparator<Apple>() {
    public int compare(Apple a1, Apple a2) {
        return a1.getWeight().compareTo(a2.getWeight());
    }
});
inventory.sort(comparing(Apple::getWeight));

2. 왜 아직도 자바는 변화하는가?

프로그래밍 언어의 세계는 생태계와도 같고 진화하지 않으면 도태되어 사라집니다.

그러므로 자바는 자바 8, 9, 10, 11.. 계속해서 발전 했고, 가장 큰 발전이었던 자바 8의 밑바탕을 이루는 세 가지 프로그래밍 개념을 알아보겠습니다.

1. 스트림

  • 스트림 : 한 번에 한 개씩 만들어지는 연속적인 데이터 항목들의 모임

2. 동작 파라미터화로 메서드에 코드 전달하기

  • 동작 파라미터화 : 메서드를 변수처럼 다른 메서드의 파라미터로 던짐으로써 메서드가 다양한 동작을 수행할 수 있게 합니다.

3. 병렬성과 공유 가변 데이터

  • 다른 코드와 동시에 실행하더라도 안전하게 실행할 수 있는 코드를 만드려면 함수를 순수함수, 부작용 없는 (side-effect-free) 함수, 상태 없는 (stateless) 함수를 만들어야 합니다.
  • 순수함수 : 공유 가변 데이터에 접근하지 않아야 합니다.

3. 자바 함수

1. 메서드와 람다를 일급 시민으로

  • 메서드 참조 : 메서드를 값으로 참조할 수 있습니다. ::을 이용하면 가능합니다.
  • 람다 : 익명 함수. (int x) -> x + 1x라는 인수를 호출하면 x+1을 반환이라는 동작을 수행하는 람다이다.

자바의 메소드 전달과 람다 예시

class Apple{

  public static void main(String[] args) {
    List<Apple> inventory = new ArrayList<>();
    inventory.add(new Apple(80, "green"));
    inventory.add(new Apple(155, "green"));
    inventory.add(new Apple(120, "red"));

    //메서드 전달
    List<Apple> heavyApples = filterApples(inventory, Apple::isHeavyApple);
    List<Apple> greenApples = filterApples(inventory, Apple::isGreenApple);
    
    //람다
    List<Apple> heavyApples = filterApples(inventory, (Apple a) -> a.getWeight() > 150);
    List<Apple> greenApples = filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
  }
  
  public static boolean isHeavyApple(Apple apple) {
    return apple.getWeight() > 150;
  }

  public interface Predicate<T> {
    boolean test(T t);
  }

  public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> p) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple : inventory) {
      if (p.test(apple)) {
        result.add(apple);
      }
    }
    return result;
  }
}

4. 스트림

스트림 적용전 ⛔️

Map<Currency, List<Transaction>> transactionsByCurrencies = new HashMap<>();
for (Transaction transaction : transactions) {
    if (transaction.getPrice() > 1000) {
        Currency currency = transaction.getCurrency();
        List<Transaction> transactionsForCurrency = transactionsByCurrencies.get(currency);
        if (transactionsForCurrency == null) {
            transactionsForCurrency = new ArrayList<>();
            transactionsByCurrencies.put(currency, transactionsForCurrency);
        }
        transactionsForCurrency.add(transaction);
    }
}

스트림 적용후 ☘️

Map<Currency, List<Transaction>> transactionsByCurrencies = transactions.stream()
    .filter((Transaction t) -> t.getPrice() > 1000)
    .collect(groupingBy(Transaction::getCurrency));

멀티스레딩은 어렵다

  • 자바 8의 스트림 API는 컬렉션을 처리하면서 발생하는 모호함과 반복적인 코드 문제 그리고 멀티코어 활용의 어려움이라는 두 가지 문제를 모두 해결했다.
  • 스트림과 람다를 사용하면 병렬성을 공짜로 얻을 수 있다. 아래 예시 코드가 있다.
    // 순차 처리
    List<Apple> heavyApples = inventory.stream()
      .filter((Apple a) -> a.getWeight() > 150)
      .collect(toList());
    // 병렬 처리
    List<Apple> heavyApples = inventory.parallelStream()
      .filter((Apple a) -> a.getWeight() > 150)
      .collect(toList());
    

5. 디폴트 메소드와 자바 모듈

  • 자바 8은 구현 클래스에서 구현하지 않아도 되는 메서드를 인터페이스에 추가할 수 있는 디폴트 메소드라는 기능을 제공한다.
  • 디폴트 메서드를 이용하면 기존의 코드를 건드리지 않고 인터페이스 설계를 자유롭게 확장할 수 있다.

6. 함수형 프로그래밍에서 가져온 다른 유용한 아이디어

댓글남기기