java8
Hello World
- 일반적인 자바 스레드 실행 코드
public class HelloWorld {
public static void main(String[] args) {
Runnable r = new InnerHelloWorld();
Thread t = new Thread(r);
t.start();
// new Thread(new InnerHelloWorld()).start();
}
// Runnable 인터페이스를 구현, inner 클래스로 지정
public static class InnerHelloWorld implements Runnable {
@Override
public void run() {
System.out.println("Hello world");
}
}
}
- java8에서의 람다식을 이용한 스레드 실행 코드
public class HelloWorld_java8 {
public static void main(String[] args) {
new Thread(
() -> {System.out.println("Hello World!");}
).start();
}
}
함수형 인터페이스 functional interface
public interface Runnable { // 인터페이스 정의
public abstract void run(); // 추상 메소드가 단 하나
}
- 추상 메소드가 하나 뿐인 모든 인터페이스
- A Functional Interface is any interface with a single abstract method.
- 단일 함수(기능) 규약
- Runnable 함수형 인터페이스 인정!
- 다수 디폴트 메소드와 정적 메소드 포함 가능
기본제공 함수형 인터페이스
- java.util.function 패키지
- 만들지 말자! 가져다 쓰자! (Don't Reinventing the wheel)
- Predicate, Consumer, Function, Supplier, UnaryOperator, BinaryOperator
람다식 lambda expression
syntax : ( 인자 ) -> { 구문 }
- 메소드와 비슷, JSR335
- 람다식은 '익명 메서드 anonymous method (이름 없는 메서드)'라 생각하자
- 대상 타입 추론, 매개변수 타입 추론 by compiler
람다식은 함수 인터페이스의 구현체로 변환
// java8 람다식을 이용한 스레드 실행 코드 new Thread(() -> { System.out.println("Hello World!"); }).start(); // 익명 클래스로 구현한 코드로 이해하기 new Thread(new Runnable() { @Override public void run() { System.out.println("Hello world"); } }).start(); }
* syntax : 문법, 구조, 또는 언어 문장 내에 있는 구성요소의 순서
* JSR : Java Specification Requests
다양한 람다식 축약형
- 람다 표현식을 더 간략하게 작성
람다식 적용
- 제어 흐름 중복 DRY > 재사용
- OOP 제어 흐름 추상화 기법을 대체 : 템플릿 메소드 패턴(상속), 전략 stratage 패턴(위임)
- 제어 흐름 추상화를 위한 행위 매개변수
행위 매개변수 parameterized behaviors
- 행위를 메소드 인자로 전달 : functional interface를 사용해서 행위(익명클래스, 람다식)를 매개변수로 전달
- 객체가 아닌 메소드(함수) 수준으로 제어 흐름을 추상화, 로직 조합(전략패턴), 콜백 전달(옵저버패턴)
- 객체를 사용하지 않는 경량
- 고차함수 higher order function : 다른 함수를 인자로 받거나 그 결과로 함수를 반환하는 함수다.
* 객체 사용 비용
- class 안에 코드를 구현, 클래스 이름, 상용구 boilerplate code, 캡슐화, 간접접근
* 행위 매개변수 보급
- 다양한 언어에서 고차함수 지원, C++ 11, C# 3.0, .Net(LINQ), Guava, LambdaJ, Op4J
- 함수형 프로그래밍 대중화 (멀티 코어 CPU)
- spring xxxTemplage
익명 클래스
- 적은 비용
- 클래스 이름 불필요, 생성자 불필요
- 클래스 생성과 인스턴스 생성이 동시, 클래스 하나에 인스턴스 하나
- 문제점 : 매번 객체 생성, 클래스 선언 > 정작 중요한 건 override한 메소드의 구현 부분
람다 != 익명 클래스
- compiler 처리가 다름
- 람다식은 invokedynamic (JSR 292)
클로저 closure
- 익명 클래스 + 변수 포획 captured variable
- 내부 객체는 외부 객체의 멤버 변수(final)에 접근 가능
- effectively final : 멤버 변수가 final이 아니더라도 수정되지 않으면 변수 포획
람다식에서의 this
- 람다식에서 this는 람다식을 가리키지 않음 > 람다는 새로운 객체를 만들지 않음
디폴트 메소드 Default method
- 인터페이스에 기본 구현체 가능, 추가된 인터페이스의 하위 호환성 보장
- 기본 메소드는 하위 클래스에서 사용 가능함(상속)
- default 키워드, IF확장 시 재구현 (overriding) 또는 추상으로 지정가능
- 다이아몬드 문제 발생 가능 > 충돌에 따른 컴파일 오류 발생으로 회피 기법 필요 (super로 선택 혹은 순서 지정, 명시적인 오버라이드)
*하위 호환성
- 기존 클래스나 인터페이스에 새 필드, 매서드, 생성자등을 추가하면 하위 호환성이 깨짐
- 이미 컴파일 된 어플리케이션이 망가짐(바이너리 하위 호환성)
- 인터페이스의 모든 메소드는 public abstract 이므로 새로운 메소드 추가시 난리부르스
- 람다식을 적용하기 위해 자바 SDK 수정하려고 하니 인터페이스 하위 문제가 발생
정적 메소드 static method
- 인터페이스에 정적 메소드 포함 가능
- 인터페이스에 필요한 별도 유틸리티 helper 클래스 분리 불필요, name space 역할
- 클래스 메소드를 전역 함수로 사용하는 효과, 서술적인 API
- 람다식와 정적 메서드, 정적 임포트(java5)로 전역 함수 활용도 증대
메소드 참조 method reference
- 이미 만들어진 메소드의 이름을 사용해서 참조하는 표현 방식
- 람다식을 더 간략하게 표현, 람다식을 대체
- syntax : 클래스나 객체::메소드 이름
- 함수형 인터페이스 및 기존 메소드 모두 가능
메소드 참조 유형
- 정적 메소드 참조, 클래스이름::메소드 이름, Math::abs, Integer::parseInt
- 인스턴스 메소드 참조, 객체참조::멤소드 이름, System.out::println
- 람다 인자 객체 메서드 참조, 람다의 인자로 넘어오는 객체의 멤버 메소드 참조 인자의 타입명::메소드 이름, someObject::someMethod
- 생성자 참조, 클래스이름::new , someObject::new
- 상위 클래스의 메소드 참조, super::메소드 이름
- 배열 생성자, 타입명[]::new
스트림 Stream API
- java.util.stream
- 연산의 선언적 서술, 반복구조는 내부에 캡슐화되며 로직에 집중하도록 분리
- 불변 데이터
- 지연 lazy, 병렬 parallel (순차 포함)
- 무한 데이터 흐름 infinite stream
- 다양한 데이터 원천 지원 : 컬렉션, 파일I/O
- 다양한 소스 : Stream, Collection, BufferedReader, Random, Arrays, Stream.builder, BitSet
스트림과 컬렉션
- collection (list, map, set)보다 높은 추상화, stream을 통한 다양한 연속적 데이터 적용
- 컬렉션은 보관용 자료구조 <> 스트림은 처리용 자료구조
스트림 연산
- 내부 반복 Internal Iteration (로직에 집중)<> 외부반복 External iteration (명시적인 제어 흐름 고려)
- 중개 연산자 : 무상태 연산 map, filter, flatMap, skip, limit, sorted, distinct
- 종단 연산자 : 결과 생산 forEach, collect, reduce, iterator
- 지연 연산 lazy : 중개 연산은 캐쉬되며 즉시 수행하지 않고 종단 연산 시점에 수행
- 병렬 처리 : parallel() 지원, 쉬운 병렬 전환