람다식이란?
기존의 객체 지향 프로그램 체계 안에서 함수형 프로그래밍을 가능하게 하는 기법
단 하나의 추상 메서드만을 포함하는 인터페이스를 함수형 인터페이스라 하고,
이 함수형 인터페이스의 호출 및 기능을 구현하는 방법을 새롭게 정의한 문법이다.
익명 이너 클래스의 축약된 형태라고 볼 수 있고, 단 하나의 추상 메서드만을 가진 함수형 인터페이스만 람다식으로 표현할 수 있다.
1.구현 메서드의 약식 표현
인터페이스 구현 메서드 -> 람다식 변환
(입력매개변수) -> {
// 메서드 내용
}
함수형 인터페이스의 객체를 생성하기 위한 람다식 표현 방법
interface A{
void method1();
}
interface B{
void method2(int a);
}
interface C{
int method3();
}
interface D{
double method4(int a, double b);
}
public class Main{
public static void main(String[] args) {
A a1 = new A(){ // 익명 이너 클래스 방식
@Override
public void method1(){
System.out.println("입력 x 리턴 x 함수");
}
};
// 람다식 표현
A a2 = () -> {
System.out.println("입력 x 리턴 x 함수");
};
A a3 = () -> System.out.println("입력 x 리턴x 함수");
// 익명 이너 클래스 방식
B b1 = new B(){
@Override
public void method2(int a){
System.out.println("입력 o, 리턴 x 함수");
}
};
// 람다식 표현
B b2 = (int a) -> {
System.out.println("입력 o, 리턴 x 함수");
};
B b3 = (a) -> {
System.out.println("입력 o, 리턴 x 함수");
};
B b4 = (a) -> System.out.println("입력 o, 리턴 x 함수");
B b5 = a -> System.out.println("입력 o 리턴 x 함수");
// 익명 이너 클래스 방식
C c1 = new C(){
@Override
public int method3(){
return 4;
}
};
// 람다식 표현
C c2 = () -> {return 4;};
C c3 = () -> 4;
// 익명 이너 클래스 방식
D d1 = new D(){
@Override
public double method4(int a, double b){
return a+b;
}
};
// 람다식 표현
D d2 = (int a, double b) -> {return a+b;};
D d3 = (a, b) -> {return a+b;};
D d4 = (a, b) -> a+b;
}
}
2.메서드 참조
정의돼 있는 인스턴스 메서드 참조
클래스 객체::인스턴스 메서드명
interface A{
void abc();
}
class B{
void bcd(){
System.out.println("메서드");
}
}
public class Main{
public static void main(String[] args) {
// 익명 이너 클래스
A a1 = new A(){
@Override
public void abc(){
B b = new B();
b.bcd();
}
};
// 람다식
A a2 = () -> {
B b = new B();
b.bcd();
};
// 정의된 인스턴스 메서드 참조
B b = new B();
A a3 = b::bcd;
a1.abc();
a2.abc();
a3.abc();
}
}
익명 이너 클래스 및 람다식을 이용해 A인터페이스 객체를 생성한 것을 보면,
abc() 메서드를 호출하면 B 객체 멤버인 bcd를 호출하는 것이므로 결국 abc()는 bcd()와 동일한 셈이다.
이를 인스턴스 메서드 참조로 간단히 표현할 수 있다.
A인터페이스 내부의 abc() 메서드는 참조 변수 b객체 내부의 인스턴스 메서드 bcd()와 동일하다는 의미가 된다.
자바가 제공하는 인스턴스 메서드 참조
A a = System.out::println;
인터페이스 A의 추상 메서드인 abc()는 System.out.println()을 참조하라는 의미.
System.out 자체가 객체이므로 객체를 따로 생성할 필요없이 위와 같이 작성한다.
interface A{
void abc(int k);
}
public class Main{
public static void main(String[] args) {
A a1 = new A(){
@Override
public void abc(int k) {
System.out.println(k);
}
};
A a2 = (int k) -> {
System.out.println(k);
};
A a3 = System.out::println;
a1.abc(3);
a2.abc(3);
a3.abc(3);
}
}
정의돼 있는 정적 메소드 참조
클래스명::정적 메서드명
정적 메서드는 객체 생성 없이 클래스명으로 바로 사용할 수 있기 때문에 객체의 생성 없이 클래스명을 바로 사용한다.
interface A{
void abc();
}
class B{
static void bcd(){
System.out.println("메서드");
}
}
public class Main {
public static void main(String[] args) {
A a1 = new A(){ // 익명 이너 클래스
@Override
public void abc(){
B.bcd();
}
};
A a2 = () -> {B.bcd();}; // 람다식
A a3 = B::bcd; // 정적 메소드 참조
a1.abc();
a2.abc();
a3.abc();
}
}
첫 번째 매개변수로 전달된 객체의 인스턴스 메서드 참조
클래스명::인스턴스 메서드명
interface A{
void abc(B b, int k);
}
class B{
void bcd(int k){
System.out.println(k);
}
}
public class Main{
public static void main(String[] args) {
A a1 = new A(){ //익명 이너 클래스
@Override
public void abc(B b, int k){
b.bcd(k);
}
};
A a2 = (B b, int k) -> {b.bcd(k);}; // 람다식
A a3 = B::bcd; // 직접 정의한 인스턴스 메서드 참조
a1.abc(new B(), 3);
a2.abc(new B(), 3);
a3.abc(new B(), 3);
}
}
자바가 제공하는 인스턴스 메서드 참조
interface A{
int abc(String str);
}
public class Main{
public static void main(String[] args) {
A a1 = new A(){
@Override
public int abc(String str){
return str.length();
}
};
A a2 = (String str) -> str.length();
A a3 = String::length; // 추상 메서드 abc()는 String 클래스의 length() 메서드와 동일한 기능
System.out.println(a1.abc("안녕"));
System.out.println(a2.abc("안녕"));
System.out.println(a2.abc("안녕"));
}
}
구현된 메서드의 내부에서는 입력매개변수로 넘어온 String 객체의 length() 메서드를 호출한다.
3.생성자 참조
배열 생성자 참조
배열 타입::new
인터페이스에 포함된 추상 메서드의 구현 메서드가 new 자료형[]과 같이 배열 객체의 생성 기능만을 수행할 때
람다식의 배열 생성자 참조 방법을 사용할 수 있다.
interface A{
int[] abc(int len);
}
public class Main{
public static void main(String[] args) {
A a1 = new A(){ // 익명 이너 클래스
@Override
public int[] abc(int len){
return new int[len];
}
};
A a2 = (int len) ->{ // 람다식
return new int[len];
};
A a3= int[]::new; // 배열의 생성자 참조
int[] array1 = a1.abc(3);
int[] array2 = a2.abc(3);
int[] array3 = a3.abc(3);
}
}
클래스 생성자 참조
클래스명::new
추상 메서드를 구현할 때 new 생성자()와 같이 객체만을 생성해 리턴하면 클래스 생성자 참조를 사용할 수 있다.
interface A{
B abc(int k); // 인터페이스에 포함된 추상메서드의 매개변수에 따라 호출될 생성자가 결정
}
class B{
B(){
System.out.println("첫 번째 생성자");
}
B(int k){
System.out.println("두 번째 생성자");
}
}
public class Main{
public static void main(String[] args) {
A a1 = new A(){
@Override
public B abc(int k){
return new B(k);
}
};
A a2 = (int k) -> new B(k);
A a3 = B::new;
a1.abc(3);
a2.abc(3);
a3.abc(3);
}
}
두 번째 생성자
두 번째 생성자
두 번째 생성자
클래스가 여러 생성자를 갖고 있을 때, 인터페이스에 포함된 추상 메서드의 매개변수에 따라 어떤 생성자를 호출할지가 결정된다.
'BACK > JAVA' 카테고리의 다른 글
[JAVA] byte단위 입출력- InputStream/OutputStream (0) | 2022.10.23 |
---|---|
[JAVA] 자바로 파일 관리하기(File 클래스) (0) | 2022.10.23 |
[JAVA] 쓰레드의 6가지 상태 (0) | 2022.08.26 |
[JAVA] 프로그램, 프로세스, 쓰레드 개념 (0) | 2022.08.18 |
[JAVA] 쓰레드의 동기화(메서드 동기화, 블록 동기화) (0) | 2022.08.10 |