y=f(x)
형태의 함수로 구성된 프로그래밍 기법으로 데이터를 매개값으로 전달하고 결과를 받는 코드들로 구성되며 대용량 데이터의 처리, 이벤트 지향 프로그래밍에 적합한 기법
람다 계산법에서 사용된 식을 프로그래밍 언어에 접목해 익명 함수를 생성하기 위한 식으로 사용되며 코드가 매우 간결해지고 컬렉션 요소를 필터링 또는 매핑해서 쉽게 집계 가능
(타입 매개변수, ...) -> {실행문;...}
람다식은 함수적 인터페이스의 익명 구현 객체로 취급됨
Runnable runnable = new Runnable(){
public void run(){...}
}
Runnable runnable = () -> {...};
/// run() 함수의 구현 객체가 됨
(타입 매개변수, ...) -> {실행문; ...}
를 통해 함수적 스타일의 람다시 ㄱ장성 가능
(a) -> {System.out.println(a);}
a -> {System.out.println(a);}
a -> System.out.println(a)
() -> {System.out.println("hello");
(x, y) -> {return x+y;}
(x, y) -> x+y
람다식이 대입되는 인터페이스로 익명 구현 객체 만들 인터페이스를 의미
람다식은 하나의 메소드를 정의하기 때문에 하나의 추상 메소드만 선언된 인터페이스만 타겟 타입이 될 수 있음
하나의 추상 메소드만 선언된 인터페이스를 함수적 인터페이스라고 하며 @FunctionalInterface
어노테이션을 통해 컴파일러가 체크하도록 함
@FunctionalInterface
public interface MyFunctionalInterface{
public void method();
}
MyFunctionalInterface fi = () -> {...}
fi.method();
@FunctionalInterface
public interface MyFunctionInterface{
public void method(int x);
}
MyFunctionalInterface fi = (x) -> {...}
MyFunctionalInterface fi = x -> {...}
fi.method(5);
@FunctionalInterface
public interface MyFunctionalInterface{
public int method(int x, y);
}
MyFunctionalInterface fi = (x, y) -> {...; return value;}
람다식 실행 블록에는 클래스 멤버인 필드, 메소드를 제약 없이 사용할 수 있기 때문에 람다식 실행 블록 내에서 this는 람다식을 실행한 객체의 참조
public class ThisExample{
public int outterField = 10;
class Inner{
int innerField = 20;
void method(){
MyFunctionalInterface fi = () -> {
System.out.println("outterField : " + outterField);
System.out.println("outterField : " + This.Example.this.outterField + "\n");
System.out.println("innerField: " + innterField);
System.out.println("innterField:" + this.innerField + "\n");
};
fi.method();
}
}
}
람다식은 함수적 인터페이스의 익명 구현 객체를 생성하기 때문에 람다식에서 사용하는 외부 로컬 변수는 final 특성을 가짐
public class UsingLocalVariable{
void method(int arg){
int localVar = 40;
//arg = 31;
//localVar = 41;
MyFunctionalInterface fi = () -> {
System.out.println("arg: " + arg);
System.out.println("localVar : " + localVar + "\n");
};
fi.method();
}
}
한 개의 추상 메소드를 가지는 인터페이스들은 모두 람다식 사용 가능
java.util.function
매개타입으로 사용되어 람다식을 매개값으로 대입할 수 있도록 해줌
매개값은 있고 리턴값이 없는 추상 메소드 accept()
가지고 있어 단지 매개값을 소비하는 역할만 수행
인터페이스 명 | 추상 메소드 | 설명 |
---|---|---|
Consumer<T> | void accept(T t) | 객체 T 받아서 소비 |
BiConsumer<T,U> | 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 값 받아 소비 |
매개값은 없고 리턴값만 있는 추상 메소드 getXXX()
가지고 있으며 실행 후 호출한 곳으로 데이터를 반환하는 역할
인터페이스 명 | 추상 메소드 | 설명 |
---|---|---|
Supplier<T> | T get() | 객체 리턴 |
BooleanSupplier | Boolean getAsBoolean() | boolean 값 리턴 |
DoubleSupplier | double getAsDouble() | double 값 리턴 |
IntSupplier | int getAsInt() | int 값 리턴 |
LongSupplier | long getAsLong() | long 값 리턴 |
매개값과 리턴값 모두 있는 추상 메소드 applyXXX()
가지고 있어 매개값을 리턴값으로 매핑(타입 변환)하는 역할
public class FunctionExample{
private static List<Student> list = Arrays.asList(
new Student("aa", 50, 60);
new Student("bb", 60, 20);
);
public static void avg(ToIntFunction<Student> function){
int sum = 0;
for(Student student : list){
sum += function.applyAsInt(student);
}
double avg = (double) sum / list.size();
}
public static void main(String[] args){
double engAvg = avg(t -> t.getEngScore());
System.out.println(engAvg);
double mathAvg = avg(t -> t.getMathScore());
System.out.println(mathAvg);
}
}
매개값과 리턴값 모두 있는 추상 메소드 가지고 있고 주로 매개값 연산하고 그 결과 리턴할 경우에 사용하며 Function 함수적 인터페이스와 동일한 형식이지만 매개값을 이용해서 연산 수행한 후 동일한 타입으로 리턴값 제공
매개값을 조사해서 true, false 리턴할 때 사용하며 testXXX()
메소드를 가짐
함수적 인터페이스는 디폴트 메소드를 가지고 있어 두 개의 함수적 인터페이스를 순차적으로 연결해서 실행할 수 있게 하며, 첫번째 리턴값을 두번째 매개값으로 제공해 최종 결과값을 리턴하게 해줌
andThen()
Interface AB = InterfaceA.andThen(InterfaceB);
result = InterfaceAB.method();
compose()
Function<T,R>
, DoubleUnaryOperator
, IntUnaryOperator
, LongUnaryOperator
에서만 제공함InterfaceAB = InterfaceA.compose(InterfaceB);
result = InterfaceAB.method();
Consumer 종류의 함수적 인터페이스는 처리결과 반환값 없기때문에 andThen()
, compose()
디폴트 메소드는 함수적 인터페이스의 호출 순서만 결정
Function/Operator 종류의 함수적 인터페이스는 먼저 실행한 함수적 인터페이스의 결과를 다음 함수적 인터페이스의 매개값으로 넘겨주고 최종 처리 결과를 반환
and()
, or()
, negate()
isEqual()
Predicate<T>의 정적 메소드로 Objects.equals(sourceObject, targetObject)
실행
minBy()
, maxBy()
BinaryOperator<T> 함수적 인터페이스의 정적 메소드로 Comparator를 이용해 최대 T, 최소 T를 얻는 BinaryOperator<T>를 반환
메소드 참조 통해 매개 변수의 정보 및 리턴 타입을 알아내어 람다식에서 불필요한 매개변수 제거
기본 메소드를 단순하게 호출만 하는 람다식을 간략화
IntBinaryOperator operator = (left, right) -> Math.max(left, right); IntBinaryOperator operator = Math::max;
클래스 :: 메소드
IntBinaryOperator operator = (x,y) -> Calculator.staticMethod(x, y);
operator = Calculator::staticMethod;
참조변수 :: 메소드
Calculator obj = new Calculator();
operator = (x,y) -> obj.instanceMethod(x, y);
operator = obj::instanceMethod;
클래스::instanceMethod
ToIntBiFunction<String, String> function;
function = (a,b) -> a.compareToIgnoreCase(b);
print(function.applyAsInt("Java8", "JAVA8"));
function = String::compareToIgnoreCase;
print(function.applyAsInt("Java8", "JAVA8"));
클래스::new
public Member(String id){
this.id = id;
}
Function<String, Member> function1 = Member::new;
Member member1 = function1.apply("aaa");
public Member(String name, String id){
this.name = name;
this.id = id;
}
BiFunction<String, String, Member> function2 = Member::new;
Member member2 = function2.apply("aa", "ag");