티스토리 뷰
-람다식이란?
-객체지향형 프로그래밍의 메소드 사용법 : 인터페이스 구현, 익명이너클래스, 람다식
-람다식 활용 : 익명클래스 구현 메소드 약식표현, 메소드 참조, 생성자 참조
1. 람다식이란?
함수형 프로그래밍. 함수의 구현과 호출만으로 프로그램을 만들 수 있는 것.
자바 제공하는 함수형 프로그래밍 방식 '람다식'. 함수 이름없는 익명 함수.
코드 간결화 및 병렬처리에 강함. 컬렉션 API 성능 효과적 개선(Stream)
함수적 프로그래밍 vs 객체지향형
-함수 : 독립적으로 사용. 기능, 동작 정의
void abc(){ /*기능, 동작*/ }
-메소드 : 클래스 또는 인터페이스 내부에 정의된 함수. 객체 지향에서 사용.
class A{
void abc(){ /*기능, 동작*/ }
-함수형 인터페이스 : 내부에 단 1개의 추상 메소드만 존재
interface A{
public abstract void abc(); //추상 메소드
}
→ 함수형 인터페이스만 람다식 표현 가능
2. 객체지향형 프로그래밍의 메소드 사용
함수를 호출하는 방식은 모두 같음.
(1) 인터페이스 구현한 클래스 이용
인터페이스 A를 구현한 클래스를 만들어 객체 생성 후 메소드 사용. - 객체지향형 프로그래밍 문법1
package lambda;
interface A {
void abc(); //추상메소드
}
class B implements A {
@Override
public void abc(){
System.out.println("Method 1");
}
}
public class OOPvsFP {
public static void main(String[] args){
A a1 = new B();
a1.abc(); //Method 1
}
}
(2) 익명이너클래스 사용
package lambda;
interface A {
void abc(); //추상메소드
}
class B implements A {
@Override
public void abc(){
System.out.println("Method 1");
}
}
public class OOPvsFP {
public static void main(String[] args){
//익명이너클래스
A a2 = new B(){
@Override
public void abc(){
System.out.println("Method 2 익명이너클래스");
}
};
//호출
a2.abc(); //Method 2 익명이너클래스
}
}
(3) 람다식 사용
-람다식 = 익명이너클래스 약식 표현.
package lambda;
interface A {
void abc(); //추상메소드
}
class B implements A {
@Override
public void abc(){
System.out.println("Method 1");
}
}
public class OOPvsFP {
public static void main(String[] args){
//람다식
A a3 = () -> {
System.out.println("Method 3 람다식");
};
//호출
a3.abc();
}
}
-표현 한꺼번에 모아보기
package lambda;
interface A {
void abc(); //인터페이스
}
class B implements A{
//인터페이스는 객체생성 불가. 구현한 클래스를 통해 객체 생성
@Override
public void abc() {
System.out.println("Method 1");
}
}
public class OOPvsFP {
public static void main(String[] args) {
//1. 객체지향 프로그래밍 문법1
A a1 = new B();
a1.abc(); //Method 1
//2. 객체지향 프로그래밍 문법2(익명이너클래스)
A a2 = new B() {
@Override
public void abc() {
System.out.println("Method 2 - 익명이너클래스");
}
};
a2.abc(); //Method 2 - 익명이너클래스
//3. 람다식
A a3 = () -> {
System.out.println("Method 3 - lmabda");
};
//3-1. 람다식 축약 표현
//A a3 = () -> System.out.println("Method 3 - lmabda");
a3.abc(); //Method 3 - lmabda
}//main
}
(4) 람다식 약식 표현
-생략할 수 있는 것 : 중괄호, 리턴(return), 매개변수 타입(소괄호 반드시 생략)
소괄호 생략 시 매개변수 타입은 반드시 생략.
리턴(return) 생략 시 중괄호 반드시 생략.
//1. 중괄호 생략 : 실행문 하나
A a = () -> {System.out.println(“테스트”);};
A a = () -> System.out.println(“테스트”);
//2. 매개변수 타입 생략. 소괄호 생략
A a = (int a) -> { };
A a = a { };
//3. 리턴 생략 : 실행문이 리턴만 있을 경우, 리턴 생략 시 중괄호 반드시 생략
A a = (a, b) -> {return a+b;};
A a = (a, b) -> a+b;
3. 람다식 활용
| 익명이너클래스 | 메소드 참조 | 생성자 참조 |
| 인스턴스 메소드 참조1, 2 정적 메소드 참조 |
배열 생성자 참조, 클래스 생성자 참조 |
|
| 클래스객체::인스턴스메소드이름 클래스이름::정적메소드이름 클래스이름::인스턴스메소드이름 |
배열타입::new |
(1) 익명이너클래스 내 구현 메소드의 약식 표현
익명이너클래스 내 구현 메소드를 람다식(약식)으로 표현. 이때, 함수형 인터페이스(내부에 한 개의 메소드만 포함한 인터페이스)만 가능. 왜냐하면 람다식은 메소드 이름을 생략하기 때문에 함수가 여러 개 있을 경우에는 무엇을 호출하는지 알 수 없게 되기 때문에 인터페이스 내에 추상 메소드가 여러 개일 경우 사용 불가.
-입력(매개변수) 여부, 리턴 여부에 따라 익명이너클래스 방식, 람다식 방식 표현 예시) ↓
package lambda;
//함수형 인터페이스의 객체를 생성하기 위한 람다식 표현 방법
interface A{//입력 x, 리턴x
void method1();
}
interface B{//입력 o, 리턴x
void method2(int a);
}
interface C{//입력 x, 리턴o
int method3();
}
interface D{//입력 o, 리턴o
double method4(int a, double b);
}
public class FunctionToLambdaExpression {
public static void main(String[] args) {
//인터페이스 함수 구현 -> 람다식
//1. 입력 x, 리턴x
//1-1. 익명이너클래스
A a1 = new A() {
@Override
public void method1() {
System.out.println("func - 입력 x, 리턴x");
}
};
//1-2 람다식
A a2 = () -> { System.out.println("func - 입력 x, 리턴x");};
A a3 = () -> System.out.println("func - 입력 x, 리턴x");
//2 입력 o, 리턴x
//2-1.익명이너클래스
B b1 = new B() {
public void method2(int a) {
System.out.println("func - 입력 o, 리턴x");
}
};
//2-2 람다
B b2 = (int a) -> {System.out.println("func - 입력 o, 리턴x");};
B b3 = (int a) -> System.out.println("func - 입력 o, 리턴x"); //중괄호 생략
B b4 = (a) -> System.out.println("func - 입력 o, 리턴x"); //입력매개변수 생략가능
B b5 = a -> System.out.println("func - 입력 o, 리턴x"); //입력매개변수 1개, 소괄호 생략
//3.입력 x, 리턴o
//3-1. 익명
C c1 = new C() {
public int method3() {
return 4;
}
};
//3-2 람다
C c2 = () -> {return 4;};
C c3 = () -> 4; //리턴 생략시 중괄호 함께 생략
//4.입력 o, 리턴o
//4-1.익명이너클래스
D d1 = new D() {
public double method4(int a, double b) {
return a+b;
}
};
//4-2 람다
D d2 = (int a, double b) -> { return a+b; };
D d3 = (a, b) -> { return a+b; }; //매기변수 타입 생략
D d4 = (a, b) -> a+b; //리턴 생략
}//main
}
(2) 메소드 참조
| 이미 정의된 인스턴스 메소드 참조 |
정적 메소드 참조 | 이미 정의된 인스턴스 메소드 참조 |
| 클래스객체::인스턴스메소드이름 | 클래스이름::정적메소드이름 | 클래스이름::인스턴스메서드이름 |
(2-1) 이미 정의된 인스턴스 메소드 참조 클래스객체::인스턴스메소드이름
리턴타입과 매개변수 동일
package lambda;
interface A {
void abc();
}
class B {
void bcd() { //이미 정의된 인스턴스 메소드
System.out.println("Method");
}
}
public class RefOfInstanceMethod_Type2_1 {
public static void main(String[] args) {
//1 익명이너클래스
A a1 = new A() {
@Override
public void abc() {
B b = new B(); //(익명이너클래스 내부 객체 생성)
b.bcd();
}
};
//2 람다식
A a2 = () -> {
B b = new B();
b.bcd();
};
//3 이미 정의된 인스턴스 참조
B b = new B();
A a3 = b::bcd;
//출력
a1.abc();
a2.abc();
a3.abc();
}
}
(2-1_2) 이미 정의된 인스턴스 메소드 참조
매개변수가 있는 경우
package lambda;
interface A {
void abc(int k);
}
public class RefOfInstanceMethod_Type2_2 {
public static void main(String[] args) {
//1. 익명
A a1 = new A(){
@Override
public void abc(int k) {
System.out.println(k);
}
};
//2 람다
A a2 = (int k) -> System.out.println(k);
//3 인스턴스메소드 참조
A a3 = System.out::println; //클래스 객체::인스턴스메소드 이름
a1.abc(3); //3
a1.abc(3); //3
a1.abc(3); //3
}//main
}
(2-2) 정적 메소드 참조 클래스이름::정적메소드이름
package lambda;
interface A{
void abc();
}
class B{
static void bcd() {
System.out.println("static metohd");
}
}
public class RefOfStaticMethod_Type {
public static void main(String[] args) {
//1.익명이너클래스
A a1 = new A() {
@Override
public void abc() {
//static method 객체 생성 필요없이 바로 접근
B.bcd();
}
};
//2 람다
A a2 = () -> B.bcd();
//3 정적 메소드 참조 클래스메소드이름::정적메소드이름
A a3 = B::bcd;
//호출
a1.abc(); //static metohd
a2.abc(); //static metohd
a3.abc(); //static metohd
}
}
(2-3) 인스턴스 메소드 참조 2 클래스이름::인스턴스메서드이름
첫번째 매개변수로 전달된 객체의 메소드를 참조
package lambda;
interface A{
void abc(B b, int k);
}
class B{
void bcd(int k) {
System.out.println(k);
}
}
public class RefOfInstanceMethod_Type2_3_1 {
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;
//호출 //(클래스 객체, int k)
a1.abc(new B(), 3); //3
a2.abc(new B(), 4); //4
a3.abc(new B(), 5); //5
}
}
*자바가 제공하는 인스턴스 메소드 참조(String str)
package lambda;
interface A {
int abc(String str);
}
public class RefOfInstanceMethod_Type2_3_2 {
public static void main(String[] args) {
//1익명이너클래스
A a1 = new A() {
@Override
public int abc(String str) {
return str.length();
}
};
//2 람다
A a2 = (String str) -> { return str.length(); };
A a3 = (String str) -> str.length(); //축약
//3. 자바가 제공하는 인스턴스 메소드 참조 매개변수 클래스이름::메소드이름
A a4 = String::length;
System.out.println(a1.abc("hello")); //5
System.out.println(a2.abc("hello")); //5
System.out.println(a4.abc("hello")); //5
}
}
(3) 생성자 참조
(3-1) 배열 생성자 참조
배열 생성자 참조, 클래스 생성자 참조 배열타입::new
interface 메소드의 리턴타입 = 배열 객체
배열 생성자 참조를 위해서는 인터페이스 메소드의 매개변수로 배열의 길이 전달.
package lambda;
interface A{
int[] abc(int len);
}
public class RefOfArrayConstructor {
public static void main(String[] args) {
// 1.익명이너클래스
A a1 = new A() {
@Override
public int[] abc(int len) {
return new int[len]; //배열 객체 생설할 때 크기 지정. 매개변수로
}
};
//2람다
A a2 = (int len) -> { return new int[len]; };
//3 배열 생성자 참조
A a3 = int[]::new;
// 생성? 출력
int[] array1 = a1.abc(3);
System.out.println(array1.length); //3
int[] array2 = a2.abc(3);
System.out.println(array2.length); //3
int[] array3 = a3.abc(3);
System.out.println(array3.length); //3
}
}
(3-2) 클래스 생성자 참조 클래스이름::new
interface 메서드의 리턴타입=클래스 객체
-매개변수 없는 경우
package lambda;
interface A{
B abc();
}
class B {
B(){
System.out.println("1st 생성자");
}
B(int k){
System.out.println("2nd 생성자");
}
}
public class RefOfArrayConstructor_1 {
public static void main(String[] args) {
//1익명이너클래스_1
A a1 = new A() {
@Override
public B abc() {
return new B();
}
};
//람다
A a2 = () -> { return new B(); };
A a3 = () -> new B();
//3 클래스 생성자
A a4 = B::new;
a1.abc(); //1st 생성자
a2.abc(); //1st 생성자
a4.abc(); //1st 생성자
}
}
-매개변수 있을 경우
package lambda;
interface A{
B abc(int k);
}
class B {
B(){
System.out.println("1st 생성자");
}
B(int k){
System.out.println("2nd 생성자");
}
}
public class RefOfArrayConstructor_2 {
public static void main(String[] args) {
//1익명이너클래스_1
A a1 = new A() {
@Override
public B abc(int k) {
return new B(k);
}
};
//람다
A a2 = (int k) -> { return new B(k); };
A a3 = (int k) -> new B(k);
//3 클래스 생성자
A a4 = B::new;
a1.abc(3); //2nd 생성자
a2.abc(3); //2nd 생성자
a4.abc(3); //2nd 생성자
}
}
End
'수업 > └Java' 카테고리의 다른 글
| [CH16_3]Java IO(Input/Output) - char 단위 입출력 (0) | 2022.02.09 |
|---|---|
| [CH16_1]파일(File)과 문자셋(Charset) (0) | 2022.02.09 |
| [CH14_1]컬렉션 프레임워크 : List<E> (0) | 2022.02.08 |
| [CH12]Thread (0) | 2022.02.07 |
| [실습문제6_1]Person, Customer, Test (0) | 2022.02.04 |
- Total
- Today
- Yesterday
- 변수
- empty-cell
- border-spacing
- scanner
- html input type
- 기본선택자
- initialized
- typeof
- html pre
- html a tag
- A%B
- selcetor
- input type 종류
- css
- 외부구성요소
- ScriptTag
- BAEKJOON
- improt
- CascadingStyleSheet
- JavaScript
- 스크립태그
- text formatting
- caption-side
- Java
- html atrribute
- html
- 입력양식
- html base tag
- 미디어 태그
- html layout
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |