java 8 람다식 소개와 의미 고찰
DESCRIPTION
Java 8의 람다식(Lambda Expression)의 사용 방법과 람다가 도입된 이유, 람다와 함께 추가된 API, 언어적인 변화를 간단히 정리TRANSCRIPT
자바 8 람다의 이해와 의미
Java 8 Lambda자바 8의 핵심 개선 사항인 람다의 정확한 성격을 고찰하고 람다가 자바 개발에 미칠 영향을 얘기합니다.
박성철
속성 주입식 람다 설명
인터페이스(Interface)
함수형 인터페이스(Functional Interface)
함수형 인터페이스(Functional Interface)
추상 메서드가 하나 뿐인 모든 인터페이스
package����������� ������������������ java.lang;����������� ������������������ !public����������� ������������������ interface����������� ������������������ Runnable����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ abstract����������� ������������������ void����������� ������������������ run();����������� ������������������ }
인터페이스
메서드 하나
함수형 인터페이스 인정!
Runnable
public����������� ������������������ class����������� ������������������ AsyncHelloWorld����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ class����������� ������������������ HelloWorld����������� ������������������ implements����������� ������������������ Runnable����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ run()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ System.out.println("Hello����������� ������������������ World!");����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String[]����������� ������������������ args)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ new����������� ������������������ Thread(new����������� ������������������ HelloWorld()).start();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
자바 ~7 쓰레드 생성
클래스 정의
객체 생성
public class AsyncHelloWorld { public static void main(String[] args) { new Thread(() -> { System.out.println("Hello World!"); }).start(); }}
자바 8 쓰레드 생성
람다식
자바 7 vs. 자바 8
public����������� ������������������ class����������� ������������������ AsyncHelloWorld����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ class����������� ������������������ HelloWorld����������� ������������������ implements����������� ������������������ Runnable����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ run()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ System.out.println("Hello����������� ������������������ World!");����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String[]����������� ������������������ args)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ new����������� ������������������ Thread(new����������� ������������������ HelloWorld()).start();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
public����������� ������������������ class����������� ������������������ AsyncHelloWorld����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String[]����������� ������������������ args)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ new����������� ������������������ Thread(()����������� ������������������ ->����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ System.out.println("Hello����������� ������������������ World!");����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }).start();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
람다식 문법
(인자 목록) -> { 구문 }
람다식 = 익명 메서드
public����������� ������������������ void����������� ������������������ sayHello(PrintStream����������� ������������������ out)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ out.println("Hello����������� ������������������ World!");����������� ������������������ }
(PrintStream����������� ������������������ out)����������� ������������������ ->����������� ������������������ {����������� ������������������ out.println("Hello����������� ������������������ World!");}
대상 타입 추론
new����������� ������������������ Thread(()����������� ������������������ ->����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ System.out.println("Hello����������� ������������������ World!");����������� ������������������ }).start();
public����������� ������������������ Thread(Runnable����������� ������������������ target)
new����������� ������������������ Thread(����������� ������������������ new����������� ������������������ Runnable()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ run()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ System.out.println("Hello����������� ������������������ World!");����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }).start();
대상 타입(Target Type)함수형 인터페이스
public����������� ������������������ interface����������� ������������������ Runnable����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ abstract����������� ������������������ void����������� ������������������ run();����������� ������������������ }
≃
매개변수 타입 추론
b.addActionListener((ActionEvent e) -> {! counter.inc();! text.setText(“버튼 클릭: " + counter.count() + " 회");! });
public����������� ������������������ void����������� ������������������ addActionListener(ActionListener����������� ������������������ l)
b.addActionListener((e) -> {! counter.inc();! text.setText(“버튼 클릭: " + counter.count() + " 회");! });
public����������� ������������������ interface����������� ������������������ ActionListener����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ void����������� ������������������ actionPerformed(ActionEvent����������� ������������������ e);����������� ������������������ }����������� ������������������
(n,����������� ������������������ str)����������� ������������������ ->����������� ������������������ str����������� ������������������ +����������� ������������������ n
람다식 예
(int����������� ������������������ n,����������� ������������������ String����������� ������������������ str)����������� ������������������ ->����������� ������������������ str����������� ������������������ +����������� ������������������ n
str����������� ������������������ ->����������� ������������������ str����������� ������������������ +����������� ������������������ 1
()����������� ������������������ ->����������� ������������������ “Hello,����������� ������������������ World!”
(int����������� ������������������ n,����������� ������������������ String����������� ������������������ str)����������� ������������������ ->����������� ������������������ {����������� ������������������ return����������� ������������������ str����������� ������������������ +����������� ������������������ n;}
()����������� ������������������ ->����������� ������������������ {}
요약
•함수형 인터페이스
•람다식 (인자 목록) -> { 구문 블럭 } 또는 (인자 목록) -> 식
•람다식 = 익명 메서드
•대상 타입
•매개변수 타입 추론
•다양한 축약형 람다식
람다식은 뭐에 써 먹는 놈이냐?
https://www.flickr.com/photos/rofi/2097239111/
제어 흐름 중복
assert numbers.length > 0;!!int max = numbers[0];!for(int i=1;! i < numbers.length;! i++)! if(Math.abs(max) < ! Math.abs(numbers[i])! max = numbers[i];!return max;!
assert numbers.length > 0;!!int max = numbers[0];!for(int i=1; ! i < numbers.length; ! i++)! if(max < numbers[i])! max = numbers[i];!return max;
템플릿 메소드 패턴
AbstractMaxFinder
public findMax(list)
abstract boolean isLesser(a, b)
NaturalMaxFinderboolean isLesser(a, b)
AbsNumberMaxFinderboolean isLesser(a, b)
안 변하는 것
변하는 것
전략 패턴
<interface>Camparator
abstract boolean isLesser(a, b)
NaturalNumberComparator
boolean isLesser(a, b)
AbsNumberCamparator
boolean isLesser(a, b)
MaxFinder
public findMax(list)
안 변하는 것
변하는 것
• 제어 흐름 재사용
• 코드 중복 제거
• 유연성 향상
• 코드 변경 주기 기준 분리
제어 흐름 추상화
OOP의 제어 흐름 추상화 기법
• 상속을 통한 제어 흐름 추상화: 템플릿 메서드 패턴
• 위임을 통한 제어 흐름 추상화: 전략 패턴
https://www.flickr.com/photos/m2w2/191545978/
https://www.flickr.com/photos/chazferret/2842411103/
•메서드 호출시 값을 인자로 전달하듯 행위를 전달 •런타임에 행위를 전달받아서 미리 정해진 제어 흐름에 따라 수행 •객체가 아닌 메서드(또는 함수) 수준의 제어 흐름 추상화 •객체를 사용하는 방법보다 경량 •함수형의 고차함수(Higher Order Function)
행위 매개변수(Paramterized Behaviors)
function����������� ������������������ forEach(array,����������� ������������������ func)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ for����������� ������������������ (var����������� ������������������ i����������� ������������������ =����������� ������������������ 0;����������� ������������������ i����������� ������������������ <����������� ������������������ array.length;����������� ������������������ i++)����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ func(array[i]);����������� ������������������ }����������� ������������������ !sum����������� ������������������ =����������� ������������������ 0����������� ������������������ forEach([1,����������� ������������������ 2,����������� ������������������ 3,����������� ������������������ 4,����������� ������������������ 5],,����������� ������������������ function(number)����������� ������������������ {����������� ������������������ sum����������� ������������������ +=����������� ������������������ number����������� ������������������ })
자바스크립트의 고차함수
자바의 행위 매개변수
java.util.Collections����������� ������������������ !public����������� ������������������ static����������� ������������������ <T>����������� ������������������ T����������� ������������������ max(Collection<?����������� ������������������ extends����������� ������������������ T>����������� ������������������ coll,����������� ������������������ Comparator<?����������� ������������������ super����������� ������������������ T>����������� ������������������ comp)����������� ������������������ public����������� ������������������ static����������� ������������������ <T>����������� ������������������ T����������� ������������������ min(Collection<?����������� ������������������ extends����������� ������������������ T>����������� ������������������ coll,����������� ������������������ Comparator<?����������� ������������������ super����������� ������������������ T>����������� ������������������ comp)����������� ������������������ public����������� ������������������ static����������� ������������������ <T>����������� ������������������ void����������� ������������������ sort(List<T>����������� ������������������ list,����������� ������������������ Comparator<?����������� ������������������ super����������� ������������������ T>����������� ������������������ c)
•모든 코드는 Class 안에 정의되어야 함(함수만 인자로 사용 불가).•모든 자바 소스 파일에 공개 클래스(public class)나 인터페이스 하나 - 자바 코드 관례•클래스 이름 작명 필요•각종 상용구(boilerplate code)•캡슐화, 간접 접근
자바 객체 사용 비용
익명 클래스
List<User>����������� ������������������ users����������� ������������������ =����������� ������������������ new����������� ������������������ ArrayList<User>();����������� ������������������ Collections.sort(users,����������� ������������������ new����������� ������������������ Comparator<User>()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ int����������� ������������������ compare(User����������� ������������������ user1,����������� ������������������ User����������� ������������������ user2)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ user1.getAge()����������� ������������������ -����������� ������������������ user2.getAge();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ });
익명 클래스를 사용한 행위 인자
• 가장 비용이 적게 드는 클래스• 클래스 정의와 인스턴스 생성이 동시• 클래스 이름 작명 불필요런• 클래스 생성자 작성 불필요• 1 회용 클래스: 클래스 하나에 인스턴스 하나
변수 포획(Captured Variable)
Button b = new Button("누르시오”);final TextField text = new TextField(20);final Counter counter = new Counter();!b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { counter.inc(); text.setText(“버튼 클릭: " + counter.count() + " 회"); }});
• 내부 객체는 외부객체의 멤버와 외곽 범주(scope)의 변수 값에 접근 가능 • 내부 객체가 접근할 변수는 final 수정 기호로 고정되어야 함
익명 클래스( + 변수 포획) = 자바식 클로저(Closure)
https://www.flickr.com/photos/chazferret/2842411103/
템플릿-콜백 패턴
행위 매개변수의 보급
• 다양한 언어에서 고차함수 지원• 함수형 프로그래밍 대중화• 스프링 xxxTemplate• C# 3.0 람다식 지원 & .Net 프레임워크(LINQ) (2007)• 자바의 수다스러운 구문에 대한 반발: Guava, LambdaJ, Op4j
List<Actor>����������� ������������������ actors����������� ������������������ =����������� ������������������ this.jdbcTemplate.query(����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ "select����������� ������������������ first_name,����������� ������������������ last_name����������� ������������������ from����������� ������������������ t_actor",����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ new����������� ������������������ RowMapper<Actor>()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ Actor����������� ������������������ mapRow(ResultSet����������� ������������������ rs,����������� ������������������ int����������� ������������������ rowNum)����������� ������������������ throws����������� ������������������ SQLException����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Actor����������� ������������������ actor����������� ������������������ =����������� ������������������ new����������� ������������������ Actor();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ actor.setFirstName(rs.getString("first_name"));����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ actor.setLastName(rs.getString("last_name"));����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ actor;����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ });
스프링 프레임워크의 JdbcTemplate 사용 예
람다식 지원 필요 급증
결국…
List<User>����������� ������������������ users����������� ������������������ =����������� ������������������ …⋯����������� ������������������ Collections.sort(users,����������� ������������������ new����������� ������������������ Comparator<User>()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ int����������� ������������������ compare(User����������� ������������������ u1,����������� ������������������ User����������� ������������������ u2)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ u1.getAge()����������� ������������������ -����������� ������������������ u2.getAge();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ });
List<User>����������� ������������������ users����������� ������������������ =����������� ������������������ …⋯����������� ������������������ Collections.sort(users,����������� ������������������ (u1,����������� ������������������ u2)����������� ������������������ ->����������� ������������������ u1.getAge()����������� ������������������ -����������� ������������������ u2.getAge());
요약
• 제어 흐름의 중복과 추상화
• OOP 방식: OOP is not a one-size-fits-all solution.
• 행위 매개변수를 사용한 제어 흐름 추상화
• 가장 비용이 적게 드는 익명 클래스
• 변수 포획
• 행위 매개변수의 대중화
• 자바, 람다식 지원
스트림(Streams) API
https://www.flickr.com/photos/23209605@N00/2786126623/
반복의 내재화
for(int����������� ������������������ n:����������� ������������������ numbers)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ …⋯����������� ������������������ }
numbers.forEach(n����������� ������������������ ->����������� ������������������ …⋯)
Collection Stream
외부 반복External Iteration
내부 반복Internal Iteration
• 명시적 외부 반복• 제어 흐름 중복 발생• 효율적이고 직접적인 요소 처리• 지저분한 코드• 유한 데이터 구조 API
• 반복 구조 캡슐화• 제어 흐름 추상화• 파이프-필터 기반 API• 최적화와 알고리듬 분리• 함축적인 표현• 무한 연속 데이터 흐름 API• 데이터 외 I/O, 값 생성 등 적용
스트림 유형
DoubleStream
java.util.stream
IntStream
LongStream
Stream<T> 객체를����������� ������������������ 요소로����������� ������������������ 하는����������� ������������������ 가장����������� ������������������ 일반적인����������� ������������������ 스트림
요소가����������� ������������������ double인����������� ������������������ 스트림
요소가����������� ������������������ int인����������� ������������������ 스트림
요소가����������� ������������������ long인����������� ������������������ 스트림
java.langOptional<T> 값이����������� ������������������ 있을����������� ������������������ 수도����������� ������������������ 없을����������� ������������������ 수도����������� ������������������ 있을����������� ������������������ 때����������� ������������������ 사용
스트림 생성
stream(),����������� ������������������ parallelStream()Collection
BufferedReader lines()
Random doubles(*),����������� ������������������ ints(*),����������� ������������������ longs(*)
BitSet IntStream()
Arrays stream(*)
of(*),����������� ������������������ range(…⋯)Stream 유형
xxxStream.Builder build()
스트림 중개 연산자
Stream<R>����������� ������������������ map(Function<?����������� ������������������ super����������� ������������������ T,?����������� ������������������ extends����������� ������������������ R>����������� ������������������ mapper)����������� ������������������ T 타입의 요소를 1:1로 R 타입의 요소로 변환 후 스트림 생성
Stream<T>����������� ������������������ filter(Predicate<?����������� ������������������ super����������� ������������������ T>����������� ������������������ predicate)����������� ������������������ T 타입의 요소를 확인해서 기준에 통과한 요소만으로 새 스트림 생성
Stream<R>����������� ������������������ flatMap(Function<T,Stream<?����������� ������������������ extends����������� ������������������ R>>����������� ������������������ mapper)����������� ������������������ T 타입의 요소를 1:n으로 R 타입의 요소로 변환 후 스트림 생성, Monad bind()
Stream<T>����������� ������������������ skip(long����������� ������������������ n) 처음 n개의 요소를 제외한 나머지 요소로 새 스트림 생성
Stream<T>����������� ������������������ limit(long����������� ������������������ n)����������� ������������������ 처음 n개의 요소로 새 스트림 생성
IntStream.range(1,����������� ������������������ 100).filter(n����������� ������������������ ->����������� ������������������ n����������� ������������������ %����������� ������������������ 2����������� ������������������ ==����������� ������������������ 0).map(n����������� ������������������ ->����������� ������������������ n*n).skip(10).limit(10)
무상태 연산
중개 연산자 관련 함수형 인터페이스
java.util.function.*
!•!Predicate<T> T 타입의 인자를 검증해서 boolean 값 반환boolean test(T t)
!•!Consumer<T> T 타입의 인자를 처리 void accept(T t)
!•!Function<T,R> T 타입의 인자를 받아 R 타입의 값으로 변환R apply(T t)
!•!Supplier<T> T 타입의 값을 생성해서 반환 T get()
!•!UnaryOperator<T> T 타입의 값을 받아 T 타입의 값을 반환 T apply(T t)
!•!BinaryOperator<T> T 타입의 두 값을 받아 T타입의 값을 반환 T apply(T t, T u)
스트림 중개 연산자
Stream<T>����������� ������������������ sorted() 정렬된 스트림 생성, T 타입은 Comparable을 구현한 타입
Stream<T>����������� ������������������ sorted(Comparator<?����������� ������������������ super����������� ������������������ T>����������� ������������������ comparator)����������� ������������������ 정렬된 스트림 생성
Stream<T>����������� ������������������ distinct()����������� ������������������ 중복된 요소를 제거한 스트림 생성
내부 상태 유지 연산
스트림 종단 연산자
void����������� ������������������ forEach(Consumer<?����������� ������������������ super����������� ������������������ T>����������� ������������������ consumer)����������� ������������������ T 타입의 요소를 하나씩 처리
R����������� ������������������ collect(Collector<?����������� ������������������ super����������� ������������������ T,R>����������� ������������������ collector)����������� ������������������ T 타입의 요소를 모두 모아 하나의 자료구조나 값으로 변환
Optional<T>����������� ������������������ reduce(BinaryOperator<T>����������� ������������������ reducer)*����������� ������������������ T 타입의 요소 둘 씩 reducer로 계산해 최종적으로 하나의 값을 계산
Iterator<T>����������� ������������������ iterator() Iterator 객체 반환
IntStream.range(1,����������� ������������������ 100).filter(n����������� ������������������ ->����������� ������������������ n����������� ������������������ %����������� ������������������ 2����������� ������������������ ==����������� ������������������ 0).map(n����������� ������������������ ->����������� ������������������ n*n)����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ .skip(10)����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ .limit(10)����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ .reduce(0,����������� ������������������ Integer::sum)
지연 연산과 병렬 처리
• 스트림을 반환하는 필터와 맵 연산은 기본적으로 지연(lazy) 연산• 지연 연산을 통한 성능 최적화 (무상태 중개 연산)• 종단 연산 시 모든 연산 수행 (반복 작업 최소화)
지연 연산
• 동일한 코드로 순차 연산과 병렬 연산 모두 지원, 선택 가능• 순차 연산에서 parallel() 메서도로 병렬 연산으로 전환 가능• Collection.parallelStream()으로 병렬 처리 스트림 생성 가능• 경고: 스트림 처리 중에는 스트림 요소를 변경하지 마시오!• 쓰레드 안전하지 않은 컬렉션에서도 병렬처리 수행
병렬 처리
Stream����������� ������������������ usersStream����������� ������������������ =����������� ������������������ users.parallelStream();����������� ������������������ int����������� ������������������ sum����������� ������������������ =����������� ������������������ usersStream.filter(u����������� ������������������ ->����������� ������������������ u.getSex()����������� ������������������ ==����������� ������������������ MALE)����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ .mapToInt(u����������� ������������������ ->����������� ������������������ u.getWeight())����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ .sum();
요약
• 스트림: 컬랙션(Collection) 프레임워크보다 한 단계 더 높은 추상화 제공
• 내부 반복
• 중개 연산: 파이프와 필터, 맵(Map)
• 종단 연산: 결과 생산(Reduce)
• 지연 연산을 통한 최적화
• 병렬 처리 추상화
• 컬랙션 외 다양한 연속적 데이터에 적용
함수의 재발견?
https://www.flickr.com/photos/vestman/4908148942/
인터페이스 하위 호환성 문제
• 경직된 자바 인터페이스, 메서드 추가 후 하위 호환성 상실
• 인터페이스에 메서드 추가 후 모든 클래스를 다시 컴파일 해야 함
• 공개된 API는 불가능
• 다양한 우회 기법 활용
• 애플리케이션: 하위 호환성 포기(1)
• 자바 SDK: 무수정, 도움 객체 사용(Collections)
• Eclipse: 확장 인터페이스 추가(ISomeRole -> ISomeRoleExtension)
• 중도: 기본 추상 클래스를 통한 확장(ISomeRole -> AbstractSomeRole)
• 람다식과 함께 대규모로 자바 SDK를 수정하려고 하면서 문제 발생
(1)����������� ������������������ http://blog.jooq.org/2013/02/01/defensive-api-evolution-with-java-interfaces/
기본 메서드(Default Method)
• 인터페이스에 기본 구현 포함 가능, 추가된 인터페이스의 하위 호환성 보장
• default 키워드 사용
• 함수형 인터페이스 조건에서 제외
• 인터페이스 확장시 재구현 또는 추상(abstract)으로 재지정 가능
• 가상 확장 메서드(virtual extension methods) 또는 방어 메서드(defender
methods)라는 이름도 사용
public����������� ������������������ interface����������� ������������������ Iterator<E>����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ …⋯…⋯����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ remove()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ throw����������� ������������������ new����������� ������������������ UnsupportedOperationException("remove");����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ forEachRemaining(Consumer<?����������� ������������������ super����������� ������������������ E>����������� ������������������ action)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Objects.requireNonNull(action);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ while����������� ������������������ (hasNext())����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ action.accept(next());����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }
기본 메서드와 상속
• 클래스의 구현이 인터페이스의 기본 구현보다 우선• 가장 구체적인 구현(most specific implementation)에 우선권 부여• 다이아몬드 문제 발생 가능• 컴파일 오류 발생(T inherits unrelated defaults for x())• 명시적인 오버라이드 필요• 충돌하는 둘 이상의 수퍼타입 중 선호하는 수퍼타입을 선택할 수 있음
• 타입 다중 상속, 행위 다중 상속은 지원하지만 상태 다중 상속은 미지원
interface����������� ������������������ Robot����������� ������������������ implements����������� ������������������ Artist,����������� ������������������ Gun����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ default����������� ������������������ void����������� ������������������ draw()����������� ������������������ {����������� ������������������ Artist.super.draw();����������� ������������������ }����������� ������������������ }
인터페이스 정적 메서드
• 인터페이스에 정적 메서드 포함 가능
• 인터페이스에 필요한 정적 메서드를 별도 유틸리티 클래스로 분리할 필요 없음
public����������� ������������������ interface����������� ������������������ Function<T,����������� ������������������ R>����������� ������������������ {����������� ������������������ !����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ R����������� ������������������ apply(T����������� ������������������ t);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ static����������� ������������������ Function<?,����������� ������������������ String>����������� ������������������ toStringFunction()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ value����������� ������������������ ->����������� ������������������ value.toString();����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ static����������� ������������������ <E>����������� ������������������ Function<E,����������� ������������������ E>����������� ������������������ identity()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ value����������� ������������������ ->����������� ������������������ value;����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ static����������� ������������������ <R>����������� ������������������ Function<?,����������� ������������������ R>����������� ������������������ constant(R����������� ������������������ constantValue)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ return����������� ������������������ value����������� ������������������ ->����������� ������������������ constantValue;����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
자바 5의 정적 임포트
• 자바 5에서 클래스 맴버(또는 정적 맴버) 임포트 기능 추가import����������� ������������������ static����������� ������������������ java.lang.Math.*;����������� ������������������
• 상속 없이 특정 클래스나 인터페이스의 정적 멤버에 직접 접근상수 인터페이스 안티패턴 예방double����������� ������������������ r����������� ������������������ =����������� ������������������ cos(PI����������� ������������������ *����������� ������������������ theta);����������� ������������������
• 클래스 메서드를 전역 함수로 사용하는 효과• 클래스 메서드(정적 메서드) 사용 빈도 확대, 서술적인 API
import����������� ������������������ static����������� ������������������ org.junit.Assert.*;import����������� ������������������ static����������� ������������������ org.mockito.Mockito.*;����������� ������������������
• 람다와 인터페이스 정적 메서드와 시너지 기대
import����������� ������������������ static����������� ������������������ com.mysema.query.alias.Alias.*;����������� ������������������ !Cat����������� ������������������ c����������� ������������������ =����������� ������������������ alias(Cat.class,����������� ������������������ "cat");����������� ������������������ for����������� ������������������ (String����������� ������������������ name����������� ������������������ :����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ from($(c),cats).where($(c.getKittens()).size().gt(0)).list($(c.getName()))){����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ System.out.println(name);����������� ������������������ }
요약
• 인터페이스에 메서드 구현 허용: 기본 메서드, 정적 메서드
• 기본 메서드: 인터페이스 메서드 추가로 인한 하위 호환성 문제 해결
• 정적 메서드: 별도 헬퍼 클래스 불필요
• 자바 5의 정적 메서드 임포트, 정적 메서드, 람다식의 혼용으로 전역 함수
활용 활성화 예상
기타 등등…
https://www.flickr.com/photos/ilmungo/115943573/
익명 클래스 생성
public����������� ������������������ class����������� ������������������ SimpleApp����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String[]����������� ������������������ args)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Runnable����������� ������������������ runnable����������� ������������������ =����������� ������������������ new����������� ������������������ Runnable()����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ @Override����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ void����������� ������������������ run()����������� ������������������ {����������� ������������������ ����������� ������������������ }����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ };����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(java.lang.String[]);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Code:����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 0:����������� ������������������ new����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ #2����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ class����������� ������������������ org/fupfin/java8/lambda/SimpleApp$1����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 3:����������� ������������������ dup����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 4:����������� ������������������ invokespecial����������� ������������������ #3����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ Method����������� ������������������ org/fupfin/java8/lambda/SimpleApp$1."<init>":()V����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 7:����������� ������������������ astore_1����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 8:����������� ������������������ return
����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(java.lang.String[]);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Code:����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 0:����������� ������������������ invokedynamic����������� ������������������ #2,����������� ������������������ ����������� ������������������ 0����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ InvokeDynamic����������� ������������������ #0:run:()Ljava/lang/Runnable;����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 5:����������� ������������������ astore_1����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 6:����������� ������������������ return
람다
public����������� ������������������ class����������� ������������������ SimpleApp����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(String[]����������� ������������������ args)����������� ������������������ {����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Runnable����������� ������������������ runnable����������� ������������������ =����������� ������������������ ()����������� ������������������ ->����������� ������������������ {};����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ }����������� ������������������ }
람다 != 익명 클래스
����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(java.lang.String[]);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Code:����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 0:����������� ������������������ new����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ #2����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ class����������� ������������������ org/fupfin/java8/lambda/SimpleApp$1����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 3:����������� ������������������ dup����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 4:����������� ������������������ invokespecial����������� ������������������ #3����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ Method����������� ������������������ org/fupfin/java8/lambda/SimpleApp$1."<init>":()V����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 7:����������� ������������������ astore_1����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 8:����������� ������������������ return
����������� ������������������ ����������� ������������������ public����������� ������������������ static����������� ������������������ void����������� ������������������ main(java.lang.String[]);����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ Code:����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 0:����������� ������������������ invokedynamic����������� ������������������ #2,����������� ������������������ ����������� ������������������ 0����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ //����������� ������������������ InvokeDynamic����������� ������������������ #0:run:()Ljava/lang/Runnable;����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 5:����������� ������������������ astore_1����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ ����������� ������������������ 6:����������� ������������������ return
JSR 292
객체메서드 참조
public class AsyncHelloWorld {! private static void sayHelloWorld() { System.out.println("Hello World!"); }! public static void main(String[] args) { new Thread(() -> sayHelloWorld()).start(); }} AsyncHelloWorld::sayHelloWorld
IntStream.range(1, 32).mapToObj(Integer::toHexString)
IntStream.range(1, 10).forEach(System.out::println);
IntStream.range(-10, 10).map(Math::abs)정적 메서드
특정 객체의 메서드
임의의 객체의 메서드
사실상 final
Button b = new Button("누르시오”);TextField text = new TextField(20);Counter counter = new Counter();!b.addActionListener( e -> { counter.inc(); text.setText(“버튼 클릭: " + counter.count() + " 회"); });
final 수정기호를 명기하지 않아도 수정되지 않는다면 변수 포획