Programming/Java
자바8 소개
Youngheon
2016. 4. 27. 17:48
본 자료는 자바카페 스터디 (04/09)에 진행된 자료이며
출처는 다음과 같습니다. http://www.slideshare.net/heungrae_kim/1-introduction-to-java8
자바8의 주요 변화
- 람다표현식(Lambda Expression)
- 메서드 레퍼런스(Method Reference)
- 스트림(Stream)
- 자바함수(Function)
- 디폴트 메서드 (Default Method)
- 동작 파라메터화 (Behavior Parameterization)
추가 된 배경
간결한 코드를 위한 개발자의 요구사항
List<Apple> inventory = new ArrayList<>();
inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120,"red")))
//익명클래스를 이용하는 방법
Collection.sort(inventory, new Comparator<Apple>(){
@Override
public int compare(Apple o1, Apple o2){
return 01.getWeight().compareTo(getWeight());
}
});
//메서드 레퍼런스를 이용하는 방법
inventory.sort(comparing(Apple::getWeight));
멀티코어 CPU 대중화 (하드웨어적)
- 기존에는 멀티코어를 활용하기 위해 Thread를 사용
- Java 1 : Thread, Lock
- Java 5 : Thread Pool, Concurrent Collection
- Java 7 : Fork-Join Framework
- 자바 8에서는 병렬처리를 지원하는 Stream API지원
- Synchronized 키워드를 사용하지 않음
- 병렬 처리 코드를 JVM으로 넘겨 처리(추상화)
- parallelStream()
자바 함수
- 자바8에서는 함수를 새로운 값의 형식으로 추가 (함수를 값으로 넘김)
- Primitive Data Type : int, boolean, float
- Reference Data Type : String, new 키워드로 생성한 각종 객체들
- Method (메서드 레퍼런스) : 메서드 블럭의 메모리상 주소값
- Function (익명함수 또는 람다) : 익명함수 블록의 메모리상 주소값
- 람다와 메서드 레퍼런스를 이용하여 스트림의 기능 구현
메서드 레퍼런스
File클래스에 isHidden() 메서드가 존재하고 있지만 복잡하게 FileFilter클래스로 감싼후 new 키워드를 사용하여 인스턴스를 객체 만든 후, 파라메타로 전달
File [] hiddenFiles = new File(".").listFiles(new FileFilter(){
@Override
public boolean accept(File pathname){
return pathname.isHidden();
}
});
//File클래스가 가지고 있는 isHidden()메서드를 직접 파라메타로 전달
File[] hiddenFiles2 = new File(".").listFiles(File::isHidden);
람다(익명함수)
//File클래스를 이용하여 익명함수를 작성하여 직접 파라메타로 전달
File[] hiddenFiles3 = new File(".").listFiles(file->file.isHidden());
- 람다코드가 길어지면 메서드 레퍼런스로 넘기는 방식 구현
- 필터와 같은 집합연산은 직접 구현하지 말고 가급적 스트림 API를 사용
스트림(Stream)
- 한번에 한개씩 만들어지는 연속적인 데이터 항목들의 모임
- 자바8에서는 하려는 작업을 고수준으로 추상화하여 일련의 스트림으로 만들어 처리
- 스트림 파이프라인을 이용하면 추상화된 병렬처리 가능
List<Apple> heavyApples = inventory.stream()
.filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
List<Apple> heavyApples2 = inventory.parallelStream()
.filter((Apple a) -> a.getWeight() > 150)
.collect(toList());
디폴트 메서드
- 특정 메서드 구현을 인터페이스가 포함하는것
- 자바8에서는 Default 키워드 지원
- 기존의 인터페이스 설계를 자유롭게 확장 가능
- 개발자가 디폴트 메서드를 직접 구현할 일은 거의 없어야 한다.
- 미래에 프로그램이 쉽게 변화할 수 있는 환경을 제공
동작 파라메터화
- 전략 패턴 (Stratege Pattern)
- 알고리즘(전략)을 미리 정의해 둔 다음 런타임에 알고리즘을 선택하는 패턴
public interface ApplePredicate{
public boolean test(Apple a);
}
public class AppleWeightPredicate implements ApplePredicate{
@Override
public boolean test(Apple a){
return a.getWeight() > 150;
}
}
public class AppleColorPredicate implements ApplePredicate{
@Override
public boolean test(Apple a){
return "green".equals(a.getColor());
}
}
@SuppressWanings("unused")
public static void main(String [] args){
List<Apple> inventory = new ArrayList<>();
inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155,"green"), new Apple(120,"red")));
List<Apple> weightApples = filter(inventory, new AppleWeightPredicate());
List<Apple> colorApples = filter(inventory, new AppleColorPredicate());
}
public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple a : inventory){
if(p.test(a)){
result.add(a);
}
}
return result;
}
//필요한 전략을 런타임에 결정할 수 있다. 단, 전략을 반드시 클래스로 만들어야 하나?
//진짜 실행에 필요한 알고리즘보다, 코드를 보내기 위해 작성된 불필요한 코드량이 더 많다.
return a.getWeight() > 150;
return "green".equals(a.getColor());
익명클래스로 전환해도 불필요한 코드는 여전히 존재한다.
@SuppressWarnings("unused")
public static void main(String [] args){
List<Apple> inventory = new ArrayList<>();
inventory.addAll(Arrays.asList(new Apple(80,"green"),new Apple(155,"green"),new Apple(120,"red")));
List<Apple> weightApples = filter(inventory, new ApplePredicate(){
@Override
public boolean test(Apple a){
return a.getWeight()>150;
}
});
List<Apple> colorApples = filter(inventory, new ApplePredicate(){
@Override
public boolean test(Apple a){
return "green".equals(a.getColor());
}
});
}
public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){
List<Apple> result = new ArrayList<>();
for(Apple a : inventory){
if(p.test(a)){
result.add(a);
}
}
return result;
}
리스트 형식을 Generic으로 추상화하고 알고리즘을 람다식으로 적용
@SuppressWarnings("unused")
public static void main(String[] args){
List<Apple> inventory = new ArrayList<>();
inventory.addAll(Arrays.asList(new Apple(80,"green"),new Apple(155,"green"), new Apple(120,"red")));
List<Apple> weightApples = filter(inventory, (Apple a) -> a.getWeight()>150);
List<Apple> colorApples = filter(inventory, (Apple a) -> "green".equals(a.getColor()));
}
public static <T> List<T> filter(List<T> list, Predicate<T> p){
List<T> result = new ArrayList<>();
for(T e: list){
if(p.test(e)){
result.add(e);
}
}
return result;
}