본문 바로가기
IT 서적/JAVA in action

[책터디] 모던 자바 인 액션 (ch1. 무슨일이 일어나고 있는가?)

by Crystal.k 2020. 2. 13.

CHAPTER1

JAVA 8, 9, 10, 11 : 무슨 일이 일어나고 있는가?

자바 8에서 제공하는 새로운 기술
- 스트림 API

- 메서드에 코드를 전달하는 기법
- 인터페이스와 디폴트 메서드

* 자바8의 요구사항 :  간결한 코드, 컬티코어 프로세서의 쉬운 활용

 

* 스트림 API 사용하면 좋은점
에러를 자주 일으키며 멀티코어 cpu 를 이용하는 것보다 비용이 훨씬 비싼 키워드 synchronized를 사용하지 않아도 된다.


* 왜 언어가 진화하는가 
1. 자바가 멀티코어 병렬성을 더 쉽게 이용할 수 있도록 진화하는 과정
2. 코드를 메서드로 전달 하는 기법이 강력한 이유와 새로운 프로그래밍의 도구인 이유
3. 스트림 API가 강력한 이유와 새로운 프로그래밍의 도구인 이유
4. 디폴트 메서드, 인터페시으, 라이브러리 간결성 유지 및 재컴파일을 줄이는 데 어떻게 활용가능한지
5. JVM을 구성하는 언어에서 함수형 프로그래밍의 영향

 

 



사과의 무게를 비교해서 목록에 정렬한다. java 8 이전과 이후의 차이를 간단히 느껴보자.

Collections.sort(inventory, new Comparator(){ 
    public int compre(Apple a1, Apple a2){ 
        return a1.getWeigth().compareTo(a2.getSeight()); 
    } 
}); 
inventory.sort(comparing(Apple::getWeight)); // java 8

이제, 본격적으로 느껴보자.

자바 8 설계의 밑바탕을 이루는 세 가지 프로그래밍 개념

첫 번쨰 프로그램 개념은 "스트림처리"

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

- java 8부터, java.util.stream 패키지에 스트림 api가 추가됨, Stream<T>는 T 형식으로 구성된 항목

- 스트림 API의 핵심 : 고수준으로 추상화해서 일련의 스트림으로 만들어 처리할 수 있음.

 

두 번째 프로그램 개념은 코드 일부를 API로 전달하는 기능(동작 파라미터화로 메서드에 코드 전달하기)

 

세 번째 프로그래밍의 개념은 "병렬성을 공짜로 얻을 수 있다"라는 말에서 시작된다.(병렬성과 공유 가변 데이터)

안정하게 실행할 수 있는 코드를 위해서 공유된 가변 데이터(Shared mutable data)에 접근하지 않는 순수함수(pure), 부작용 없는 함수(side-effect-free), 상태 없는 함수(stateless)를 통해 안전하게 병렬성을 사용.

synchronized를 사용하지 않고 병렬성을 이용하는 방법을 알아본다.


File[] hiddenFiles = new File(".").lastFiles(
	new FileFilter(){
    	public boolean accept(File file){
        	return file.isHidden();
         }
    });
//JAVA 8 이후
File[] hiddenFiles = new File(".").listFiles(File::isHidden);

기존의 방식은 FileFilter 객체로 isHidden 메서드를 감싼다음에 File.listFiles 메서드를 전달해야했지만, JAVA8에서는 :: 메소드 참조 문법을 이용해서 직접 isHidden 함수를 listFiles 메서드로 전달가능하다.

 


코드 넘겨주기(메서드 전달)

Apple이라는 객체에 getColor 메소드가 존재하고, Apple을 리스트로 가지고 있는 inventory 변수에서 녹색사과 리스트를 반환하고자 하는 함수를 작성한다고 할 때 java8 이전과 이후의 코드를 확인해보자.

public static List<Apple> filterGreenApples(List<Apple> inventory){
	List<Apple> result = new ArrayList<>();
    for(Apple apple : inventory){
    	if(GREEN.equals(apple.getColor()){
        	result.add(apple);
        }
    }return result;
}
//JAVA8 이후
public static boolean isGreenApple(Apple apple){
	return GREEN.eqauls(apple.getColor());
}

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

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;
}


//이렇게 사용한다.
filterApples(inventory, Apple::isGreenApple);

 

* 프레디케이트(predicate)

위에서 Apple::isGreenApple 메서드를 filterApples로 넘겨주었다.

수학에서는 인수로 값을 받아 trure, false를 반환하는 함수를 프레디케이트라고 함.

Funstion<Apple, Boolean>으로 구현할 수 있지만, Prediate<Apple>을 사용하는 것이 표준적인 방식이고 효율적이다.

 

메서드 전달에서 람다로

위의 isGreenApple 같은 한 두번만 사용할 메서드를 매번 정의하는 것은 번거롭다. 이를 해결하기위해 람다라는 개념을 이용한다.

filterApples(inventory, (Apple a)-> GREEN.equals(a.getColor()) );

스트림

많은 자바 애플리케이션은 컬랙션을 만들고 활용한다. 스트림 API를 사용하여 컬랙션을 처리하는 방식을 보자.

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

위의 코드는 중첩된 제어 흐름 문장이 많아서 코드를 이해하기도 어렵다.

스트림 API를 이용하면 아래처럼 해결할 수 있다.

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

 

반응형

댓글