객체지향 언어인 자바에서 함수적 프로그래밍 지원 기법
함수 : 기능, 동작을 정의
void abc(){ // 기능 및 동작 }
메서드 : 클래스 또는 인터페이스 내부에서 정의된 함수
class A{
void abc() { // 기능 및 동작 }
}
함수형 인터페이스 : 내부에 단 1개의 추상 메서드만 존재하는 인터페이스
interface A{
public abstract void abc();
}
순서
함수 독립적 정의 및 구현
함수 이름 바로 사용
(자주 사용하는 기능 구현 - 람다식 표현)
자바는 새로운 함수 문법을 정의한 것이 아니라 이미 있는 인터페이스를 빌어 람다식을 표현
// 1. 인터페이스 정의
interface A{
void abc();
}
// 2. 익명이너클래스
A a = new A(){
void abc(){
// 메서드 내용
}
}
// 3. 메서드 사용
a.abc()
// 1. 인터페이스 정의
interface A{
void abc();
}
// 2. 익명이너클래스
A a = A() ->{
// 메서드 내용 (람다식)
}
}
// 3. 메서드 사용
a.abc()
void abc()
안에 메서드 내용 구현됨new A()
, abc
메서드 이름 +) 매개변수 타입즉, 람다식은 익명이너클래스를 약식으로 표현한 문법적 형태로 볼 수 있다.
모든 인터페이스의 구현 메서드는 람다식으로 변환할 수 없다.
함수적 인터페이스의 메서드만 람다식으로 표현 가능하다.
람다식의 가장 큰 특징은 정의하는 것이다.
A a = () -> System.out.println("테스트");
A a = (a, b) -> { ... };
A a = b -> { ... };
return
만 있는 경우, return
생략A a = (a, b) -> a+b;
- 익명이너클래스 내 구현 메서드의 약식(람다식)표현 →함수적 인터페이스만 가능
- 메서드 참조 (인스턴스 메서드 참조 Type1, 정적 메서드 참조, 인스턴스 메서드 참조 Type2)
- 생성자 참조 (배열 생성자 참조, 클래스 생성자 참조)
// 함수형 인터페이스
interface A{
void method(int a, double b);
}
// 1. 익명이너 클래스 활용
A a = new A(){
public void method(int a, double b){
return a+b
}
}
// 2. 람다식 활용
A a1 = (int a, double b) -> {return ...};
A a2 = (a, b) -> a+b;
이미 정의된 인스턴스 메서드 참조
interface A{
void abc();
}
class B{
/* 인스턴스 메서드 */
void bcd(){
System.out.println("메서드");
}
}
A a = new A(){
public void abc(){
B b = new B();
b.bcd();
}
}
abc()
메서드 기능 = B 객체
의 tmp()
메서드 기능서로 같다는 것을 확인할 수 있다. 이를 람다식으로 줄이면,
// 람다식으로 표현
A a = () ->
B b = new B();
b.bcd();
// 축약!
B b = new B();
A a = b ::bcd;
클래스
객체
:: 인스턴스메서드 이름
클래스 객체 속 인스턴스메서드 안에 있는 내용으로 람다식을 채워라!
interface A{
void abc(int k);
}
A a = new A(){
public void abc(int k){
System.out.println(k);
}
}
A a = System.out::println;
a.abc(30);
이미 정의된 정적 메서드 참조
interface A{
void abc();
}
class B{
static void bcd(){
System.out.println("메서드");
}
}
// 익명이너클래스 방법
A a = new A(){
public void abc(){
B.bcd();
}
}
// 람다식으로 표현
A a = () ->
B.bcd();
// 축약!
A a = B::bcd;
클래스
이름
:: 인스턴스메서드 이름
- 정적 메서드 참조를 위해서는
리턴타입과 매개변수가 동일해야 함
첫번째 매개변수로 전달된 객체의 메서드를 참조하는 경우
interface A{
void abc(B b, int k);
}
class B{
static void bcd(int k){
System.out.println(k);
}
}
// 익명이너클래스 방법
A a = new A(){
public void abc(B b, int k){
b.bcd(k);
}
}
// 람다식으로 표현
A a = (b, k) ->
b.bcd(k);
A a = B::bcd;
클래스
이름
:: 인스턴스메서드 이름
클래스 객체를 만들 필요 없이, 첫번째 매개변수로 객체를 전달해준다.
표현 방법은 정적 메서드와 동일!
A a = String::length;
a.abc("안녕"); // 2
interface A {
int abc(String str);
}
A a = new A(){
public int abc(String str){
return str.length();
}
}
A a = (str)->str.length();
배열의 new 생성자를 참조하는 경우
interface 메서드이 리턴타입 = 배열객체
interface A {
int[] abc(int len);
}
A a = new A(){
public int[] abc(int len){
return new int[len];
}
}
A a = (len)->new int[len];
// 축약!
A a = int[]::new;
배열 타입 ::
new
- 배열 생성자 참조를 위해서는
인터페이스 메서드의 매개변수로, 배열의 길이를 전달
클래스의 new 생성자를 참조하는 경우
interface 메서드의 리턴타입 = 클래스 객체
interface A {
B abc(int k);
}
class B{
B(){ // 첫번째 생성자 }
B(int k) { // 두번째 생성자 }
}
A a = new A(){
public B abc(){
return new B;
}
}
A a = ()->new B();
// 축약! -> 첫번째 생성자를 이용한 객체 생성
A a = B::new;
A a = new A(){
public B abc(int k){
return new B;
}
}
A a = (k)->new B(k);
// 축약! -> 두번째 생성자를 이용한 객체 생성
A a = B::new;
클래스
이름
:: 인스턴스메서드 이름
- 클래스 생성자 참조를 위해서는
인터페이스 메서드의 매개변수에 따라 생성자 선택