-
[Java 자바] 14. 람다식Programming/Java 2022. 9. 14. 00:26반응형
14-1. 람다식이란?
- 익명 함수를 생성하기 위한 식으로 객체 지향 언어보다는 함수 지향 언어에 가까움
- "(매개변수) -> {실행코드} " 형태로 작성
// Runnable 인터페이스의 익명 구현 객체를 생성하는 코드 Runnable runnable = new Runnable() { public void run() {...} } // 람다식을 이용해 표현할 경우 Runnable runnable = () -> {...};
14-2. 람다식 기본 문법
// 기본 형태 (타입 매개변수, ...) -> { 실행문; ... } // int 매개 변수 a 값을 콘솔에 출력할 때 (int a) -> {System.out.println(a);} // 매개 변수 타입은 런타임 시 대입값에 따라 자동으로 인식될 수 있어, // 람다식에서는 일반적으로 매개변수의 타입을 언급하지 않음 (a) -> {System.out.println(a);} // 하나의 매개변수만 있다면 괄호() 생략 가능 // 하나의 실행문만 있다면 중괄호{} 생략 가능 a -> System.out.println(a); // 매개변수가 없을 경우 빈 괄호 사용 () -> {실행문, ...} // 중괄호를 실행하고 결과값을 리턴해야 할 경우 (x, y) -> { return x + y; } // 중괄호에 return문만 있을 경우, return과 중괄호 생략 가능 (x, y) -> x + y
14-3. 타겟 타입과 함수적 인터페이스
- 람다식은 단순히 메소드를 선언하는 것이 아닌, 메소드를 가지고 있는 객체를 생성
- 람다식은 인터페이스 변수에 대입되어, 인터페이스의 익명 구현 객체를 생성함
- 람다식의 타겟 타입: 람다식이 대입될 인터페이스
인터페이스 변수 = 람다식;
14-3-1. 함수적 인터페이스 (@FunctionalInterface)
- 람다식은 하나의 메소드를 정의하기 때문에 두 개 이상의 추상 메소드가 선언된 인터페이스는 람다식을 이용할 수 없음
=> 하나의 추상 메소드가 선언된 인터페이스만이 람다식의 타겟 타입이 될 수 있으며, 이러한 인터페이스를 함수적 인터페이스라 함- @FunctionalInterface 어노테이션을 통해 두 개 이상의 추상 메소드가 선언되지 않도록 컴파일러가 체킹해줌
@FunctionalInterface public interface MyFunctionalInterface { public void method(); public void otherMethod(); // 컴파일 오류 }
14-3-2. 매개 변수와 리턴값이 없는 람다식
// MyFunctionalInterface.java @FunctionalInterface public interface MyFunctionalInterface { public void method(); } // MyFunctionalInterfaceTest.java public class MyFunctionalInterfaceTest { public static void main(String[] args) { MyFunctionalInterface fi; // method()의 매개변수가 없으므로 람다식의 매개변수도 없음 fi = () -> { String str = "method call1"; System.out.println(str); }; fi.method(); fi = () -> { System.out.println("method call2"); }; fi.method(); fi = () -> System.out.println("method call3"); fi.method(); } }
14-3-3. 매개 변수가 있고 리턴값이 없는 람다식
// MyFunctionalInterface.java @FunctionalInterface public interface MyFunctionalInterface { public void method(int x); } // MyFunctionalInterfaceTest.java public class MyFunctionalInterfaceTest { public static void main(String[] args) { MyFunctionalInterface fi; fi = (x) -> { int result = x * 5; System.out.println(result); }; fi.method(2); fi = (x) -> {System.out.println(x*5);}; fi.method(2); fi = x -> System.out.println(x*5); fi.method(2); } }
14-3-4. 매개 변수가 있고 리턴값이 있는 람다식
// MyFunctionalInterface.java @FunctionalInterface public interface MyFunctionalInterface { public int method(int x, int y); } // MyFunctionalInterfaceTest.java public class MyFunctionalInterfaceTest { public static void main(String[] args) { MyFunctionalInterface fi; fi = (x, y) -> { int result = x + y; return result; }; System.out.println(fi.method(2, 5)); fi = (x, y) -> { return x + y; }; System.out.println(fi.method(2, 5)); fi = (x, y) -> x + y; System.out.println(fi.method(2, 5)); fi = (x, y) -> sum(x, y); System.out.println(fi.method(2, 5)); } public static int sum (int x, int y) { return (x + y); } }
14-4. 클래스 멤버와 로컬 변수 사용
14-4-1. 클래스 멤버 사용
- 람다식 실행 블록에서는 클래스의 멤버인 필드와 메소드를 제약 사항 없이 사용 가능
- 단, this 키워드를 사용할 경우 익명 객체의 참조가 아닌 람다식을 실행한 객체의 참조이므로 주의// MyFunctionalInterface.java public interface MyFunctionalInterface { public void method(); } // UsingThis.java public class UsingThis { public int outterField = 10; class Inner { int innerField = 20; void method() { // 람다식 MyFunctionalInterface fi = () -> { System.out.println("outterField: " + outterField); // 바깥 객체의 참조를 얻기 위해서는 클래스명.this 사용 System.out.println("outterField: " + UsingThis.this.outterField + "\n"); System.out.println("innerField: " + innerField); System.out.println("innerField: " + this.innerField + "\n"); }; fi.method(); } } } // UsingThisTest.java public class UsingThisTest { public static void main(String[] args) { UsingThis usingThis = new UsingThis(); UsingThis.Inner inner = usingThis.new Inner(); inner.method(); } }
14-4-2. 로컬 변수 사용
- 람다식은 메소드 내부에서 주로 작성되기에 로컬 익명 구현 객체를 생성시킨다고 할 수 있음
- 메소드의 매개변수 또는 로컬 변수를 사용하려면 이 두 변수는 final 특성을 가져야 함// MyFunctionalInterface.java public interface MyFunctionalInterFace { public void method(); } // UsingLocalVariable.java public class UsingLocalVariable { void method(int arg) { // arg는 final특성을 가짐 int localVar = 40; // localVar은 final 특성을 가짐 // arg = 31; // final 특징 때문에 수정 불가 // localVar = 41; // final 특징 때문에 수정 불가 // 람다식 MyFunctionalInterface fi = () -> { System.out.println("arg: " + arg); System.out.println("localVar: " + localVar + "\n"); }; fi.method(); } } //UsingLocalVariableTest.java public class UsingLocalVariableTest { public static void main(String[] args) { UsingLocalVariable ulv = new UsingLocalVariable(); ulv.method(20); } }
14-5. 표준 API의 함수적 인터페이스
- 자바 표준 API에서 한 개의 추상 메소드를 가지는 인터페이스는 모두 람다식을 이용해 익명 객체 구현 가능
14-5-1. Consumer 함수적 인터페이스
- 리턴값이 없는 accept() 메소드를 가지고 있음
- accept() 메소드는 매개값을 받아 소비하는 역할만 함 (사용만 할 뿐 리턴값이 없다)- 매개 변수와 타입에 따라 여러 Consumer 인터페이스가 존재함
인터페이스명 추상 메소드 설명 Consumer<T> void accept(T t) 객체 T를 받아 소비 BiConsumer<T> void accept(T t, U u) 객체 T와 U를 받아 소비 DoubleConsumer void accept(double value) double 값을 받아 소비 IntConsumer void accept(int value) int 값을 받아 소비 LongConsumer void accept(long value) long 값을 받아 소비 ObjDoubleConsumer<T> void accept(T t, double value) 객체 T와 double 값을 받아 소비 ObjIntConsumer<T> void accept(T t, int value) 객체 T와 int 값을 받아 소비 ObjLongConsumer<T> void accept(T t, long value) 객체 T와 long 값을 받아 소비 // ConsumerExample.java public class ConsumerExample { public static void main(String[] args) { Consumer<String> consumer = t -> System.out.println(t + "8"); consumer.accept("Java"); } }
14-5-2. Supplier 함수적 인터페이스
- 매개 변수가 없고 리턴값이 있는 getXXX() 메소드를 가지고 있음
- 메소드는 실행 후 호출한 곳으로 데이터를 리턴(공급)하는 역할을 함
- get() 메소드가 매개값을 가지지 않으므로 람다식도 ()를 사용인터페이스명 추상 메소드 설명 Supplier<T> T get() T 객체를 리턴 BooleanSupplier boolean getAsBoolean() boolean 값을 리턴 DoubleSupplier double getAsDouble() doulbe 값을 리턴 IntSupplier int getAsInt() int 값을 리턴 LongSupplier long getAsLong() long 값을 리턴 // SupplierTest.java public class SupplierTest { public static void main(String[] args) { IntSupplier intSupplier = () -> { int num = (int) (Math.random() * 6) + 1; return num; }; int num = intSupplier.getAsInt(); System.out.println("눈의 수: " + num); } }
14-5-3. Function 함수적 인터페이스
- 매개값과 리턴값이 있는 applyXXX() 메소드를 가지고 있음
- 매개값을 리턴값으로 매핑(타입 변환) 하는 역할을 함// Student.java public class Student { private String name; private int englishScore; private int mathScore; public Student(String name, int englishScore, int mathScore) { this.name = name; this.englishScore = englishScore; this.mathScore = mathScore; } public String getName() {return name;} public int getEnglishScore() {return englishScore;} public int getMathScore() {return mathScore;} } // FunctionTest.java public class FunctionTest { private static List<Student> list = Arrays.asList( new Student("a", 90, 96), new Student("b", 95, 93) ); public static void printString(Function<Student, String> function) { for(Student student: list { System.out.print(function.apply(student) + " "); } System.out.println(); } public static void printInt (ToIntFunction<Student> function) { for(Student student : list { System.out.print(function.applyAsInt(student) + " "); } System.out.println(); } public static void main(String[] args) { System.out.println("[학생 이름]"); printString(t -> t.getName()); System.out.println("[영어 점수]"); printInt(t -> t.getEnglishScore()); System.out.println("[수학 점수]"); printInt(t -> t.getMathScore()); } }
14-5-4. Operator 함수적 인터페이스
- Function과 동일하게 매개 변수와 리턴값이 있는 applyXXX() 메소드를 가지고 있음
- 하지만 매개값을 이용해 연산을 수행한 후 동일한 타입으로 리턴값을 제공한다는 점에서 차이
// OperatorTest.java public class OperatorTest { private static int[] scores = {92, 95, 87}; public static int maxOrMin (IntBinaryOperator operator) { int result = scores[0]; for(int score = scores) { result = operator.applyAsInt(result, score); } return result; } public static void main(String[] args) { int max = maxOrMin( (a, b) -> { if (a >= b) return a; else return b; } ); int min = maxOrMin( (a, b) -> { if (a <= b) return a; else return b; } ); System.out.println("최소값 :" + min); } }
반응형'Programming > Java' 카테고리의 다른 글
[Java Spring] 스프링의 MVC 구조 (0) 2022.10.21 [Java Spring] 스프링 프레임워크란? (0) 2022.10.21 [Java 자바] 12. 멀티 스레드 ④ 스레드풀 (0) 2022.09.12 [Java 자바] 12. 멀티 스레드 ③ 데몬 스레드, 스레드 그룹 (0) 2022.09.12 [Java 자바] 12. 멀티 스레드 ② 동기화, 스레드 상태와 제어 (0) 2022.09.12