람다식은 익명 객체를 간격하게 표현하는 기법입니다. 이를 통해 코드의 간결성과 가독성을 높이며, 개발 생산성을 향상시킬 수 있습니다.
람다식을 더욱 효과적으로 활용하기 위해서 Java 클래스 개념인 중첩 클래스와 인터페이스 그리고 익명객체에 대해 먼저 이해해야 합니다.
Java 언어 공부가 아니라 OOP를 활용하기 위한 람다식 사용법을 배우는 과정이니 각 개념에 대해 세세히 다루진 않습니다. 람다식으로 진화하는 과정을 주로 다루겠습니다.
목차
- 중첩 클래스와 중첩 인터페이스 개념과 형태
- 익명 객체 개념과 형태
- 람다식 개념과 형태
1-1. 중첩 클래스
중첩 클래스는 다른 클래스 안에 정의된 클래스를 말합니다. 외부클래스는 이 내부 클래스와 밀접한 연관성을 가집니다.
같은 기능을 하는 클래스끼리 결합도를 높여 전체 코드의 복잡성을 줄여주기 때문에 OOP에서 캡슐화를 강조한 구조입니다.
중첩 클래스의 종류는 [인스턴스 멤버 / 정적 멤버 / 로컬] 중첩 클래스로 나뉩니다.
이는 내부 클래스가 외부 클래스에서 어떤 접근제한자를 가지고 어떤 위치에 선언되느냐에 따라 구분됩니다.
우선 중첩클래스는 클래스 안에 클래스를 만드는 것이라고 간단하게 알아두겠습니다.
public class OuterClass {
// 내부 클래스
public class InnerClass {
System.out.println("Hi, Sujeong");
}
}
1-2. 중첩 인터페이스.
중첩 클래스와 같은 이유로 사용하지만 외부 클래스 멤버로 클래스가 아닌 인터페이스를 선언하는 것이 중첩 인터페이스 입니다.
클래스 내부에 인터페이스를 선언하고, 인터페이스 추상 메서드를 실행하는 메서드를 외부 클래스에 선언합니다.
인터페이스를 사용하면 내용을 구현체에 맞춰 다르게 표현하기 용이합니다. 외부 클래스 입장에서 같은 추상 메서드를 실행하더라도 인터페이스의 구현체가 무엇이냐에 따라 동작이 다르게 실행됩니다.
따라서 중첩 인터페이스이는 중첩이 가지는 의미와 인터페이스의 다형적 장점을 같이 가집니다.
아래 예시는 '버튼' 클래스 안에 '같은' 메서드를 통해 다른 동작을 구현해내는 인터페이스의 다형적 성질을 보여줍니다.
또한 중첩 인터페이스를 통해 클래스 바깥에 별도의 클래스를 만들지 않고 필요한 클래스에서만 사용하게 함으로써 코드의 구조를 논리적으로 그룹화 하고 있음을 볼 수 있습니다.
public class Button {
public interface ClickListener {
void onClick(); }
private ClickListener clickListener;
public void setClickListener(ClickListener clickListener) {
this.clickListener = clickListener;
}
// 인터페이스 메서드 실행시키는 메서드 (정확히는 setter로 주입된 구현체가 정의한 onClick())
public void click() {
this.clickListener.onClick();
}
}
public class ButtonExample {
public static void main(String[] args) {
// OkListener
Button bntok = new Button();
class OkListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("ok버튼을 눌렀습니다.");
}
}
bntok.setClickListener(new OkListener());
bntok.click();
Button bntCancel = new Button();
class CancelListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("취소 버튼을 눌렀습니다.");
}
}
bntCancel.setClickListener(new CancelListener());
bntCancel.click();
}
}
정리하자면, 중첩 클래스와 인터페이스는 사용하는 형태는 다르지만, 결국 관련 있는 코드를 모아 캡슐화 한다는 점에서 같습니다.
우리는 앞으로 클래스 방식보단 다형성의 장점을 지닌 인터페이스 방식을 중점으로 다음 주제를 보도록 하겠습니다.
2. 익명객체의 개념과 형태.
익명 객체는 클래스나 인터페이스를 명시적으로 선언하지 않음으로써 객체를 쉽게 생성하기 위한 기능입니다.
새로운 클래스를 선언하지 않고, 기존의 클래스나 인터페이스를 구현하는 동시에 객체를 생성하며. 이 객체는 일반적으로 일회성 사용을 목적으로 합니다.
중첩 인터페이스와 구현 차이
중첩 인터페이스
Button
클래스 내부에 있는 중첩 인터페이스인 ClickListener
를 구현한 클래스를 꼭 명시적으로 선언하였습니다. 이후 인터페이스를 set함수를 통해 지정하고 비로소 추상 메서드를 실행하였습니다.
익명객체
익명 객체는 내부에 들어갈 추상 클래스나 인터페이스가 따로 바깥에 정의 되고, 이를 필요할 때마다 다른 클래스에서 간단히 구현할 수 있다는 것에 가치를 가집니다.
인터페이스는 재사용 할 수 있게 하면서 인터페이스의 기능을 객체에 따라 그때마다 만드는 것이 쉬워졌습니다.
결론적으로 기능을 구조별로 세분화 하고, 이를 조립하는것을 아주 간단한 문법으로 가능하게 합니다.
public interface Clickable {
void onClick();
}
public class Button {
public void click(Clickable cb) {
cb.onClick();
}
}
public class ButtonExample {
public static void main(String[] args) {
// 익명 객체 사용 전 (중첩클래스로 사용)
Button bntok = new Button();
class OkListener implements Button.ClickListener {
@Override
public void onClick() {
System.out.println("ok버튼을 눌렀습니다.");
}
}
bntok.setClickListener(new OkListener());
bntok.click();
// 익명 객체 사용
Button bnt = new Button();
bnt.click(new Clickable() {
@Override
public void onClick() {
System.out.println("버튼을 눌렀습니다.");
}
});
}
}
3. 람다식 개념과 형태
람다식은 Java8에서 도입된 기능으로, 간결해진 익명함수를 더 간결하게 표현합니다.
익명함수와 이를 람다식으로 옮긴 예시 코드.
public interface Clickable {
void onClick();
}
public class Button {
public void click(Clickable cb) {
cb.onClick();
}
}
// 익명 함수 형태
bnt.click(new Clickable() {
@Override
public void onClick() {
System.out.println("버튼을 눌렀습니다.");
}
});
// 람다식 형태
bnt.click( () -> System.out.println("버튼을 눌렀습니다."));
New 연산자 없이 어떤 인터페이스를 구현한건지를 알지?
이와 같은 의문이 들 것입니다. java가 가진 설계도, 바로 class에 답이 있습니다.
이전에 Button 클래스를 정의할 때, click() 메서드를 정의 하며 매개변수로 인터페이스를 넣어 주었습니다.
public class Button {
public void click(Clickable cb) {
cb.onClick();
}
}
java는 이런 설계도를 통해 람다식으로 표현해도 어떤 인터페이스를 구현 한것인지를 유추해냅니다.
그렇다면 또 이런 의문이 들 것입니다.
그럼 그 인터페이스 중에서 어떤 추상 메서드를 구현한건지 어떻게 아는거야?
네, 정답은 알 수 없다 입니다. 그래서 람다식의 사용 방법을 제한함으로써 이를 구분합니다.
람다식은 애초에 추상 메서드를 오직 하나만 가진 인터페이스에 대한 익명객체를 만들 때만 사용가능 합니다. 따라서 어떤 메서드를 구현한지는 알 필요가 없습니다. 메서드가 하나기 때문에 십중팔구 그. 메서드 하나를 구현한 것이기 때문입니다.
public interface Clickable {
void onClick();
// void offClick(); -> 이 코드가 있으면 람다식 사용 불가.
}
정리하자면.
람다식은 추상 메서드를 하나만 가진 인터페이스(함수형 인터페이스) 를 객체로 구현하는데 편리한 표현법입니다.
람다식은 함수형 인터페이스에서만 사용 가능하므로, 아닌 인터페이스나 추상 클래스에서 다형성을 활용하고 싶다면 익명클래스나 익명 객체 사용을 고려할 수 있습니다.
결론
다양한 Java 클래스 구조를 통해 OOP의 캡슐화와 다형성을 활용하는 방법을 설명하고, 이를 익명객체와 람다식을 통해 간결하게 표현하여 더 쉽게 활용할 수 있는 방법에 대해 설명하였습니다.
결국 익명객체나 람다식은 복잡한 클래스 구조를 간단하게 구현하여 쉽게 다형성을 구현하는 기능입니다. 따라서 객체 지향 프로그래밍을. 잘 구현하는 클래스 구조를 설계하는 것이 선행되지 않으면 해당 기능을 사용하여도 큰 효과를 보지 못합니다.
람다식이 나온 배경을 이해하고 클래스 구조를 잘 설계하여 객체 지향 프로그래밍을 할 수 있도록 노력하면 좋을 것입니다.
참고 및 약어
*OOP : Object-Oriented Programing , 객체 지향 프로그래밍
(도서) 이것이 자바다
'Tech > java' 카테고리의 다른 글
Java null-safety Programming (0) | 2024.10.07 |
---|