람다식이란 "식별자없이 실행가능한 함수"이다.
함수지만, 따로 함수를 생성하지않고 코드 한 줄에 함수를 써서 그것을 호출하는 방식이다.
함수적 프로그래밍을 위해 자바 8부터 람다식(Lambda Expressions)을 지원하면서 코드의 문법이 간결해져 가독성 면에서 장점이 돋보이다.
흔히 인터페이스는 클래스에서 상속받아 메서드를 오버라이드하며 사용된다. 또 클래스 생성없이 익명 클래스를 만들어서 사용 가능하다.
익명클래스 예시 1
public static void main(String[] args){ Myinterface m = new Myinterface(){ @Override public void print(){ System.out.println("hello"); } } m.print(); }
익명클래스 예시 2
public static void main(String[] args){ (new Myinterface() { @Override public void print(){ System.out.println("hello"); } }).print(); }
인터페이스는 매개변수로도 참조가 되어 사용이 가능하다.
매개변수 예시
public static void myMethod(Myinterface f){ f.print(); } public static void main(String[] args){ Myinterface m = new Myinterface(){ @Override public void print(){ System.out.println("hello"); } } myMethod(m); }
인터페이스를 리턴타입으로도 반환할 수 있다.
리턴타입 예시
public static Myinterface myMethod() { return new Myinterface(){ @Override public void print(){ System.out.println("hello"); } } } public static void main(String[] args){ Myinterface m = myMethod(); m.print(); }
이렇게 인터페이스를 사용할 때, 여러가지 방법이 있지만, 익명 클래스와 매개변수, 리턴타입으로 쓸 때는 코드가 복잡해지고 가독성이 떨어지는 단점때문에자바 8버전부터는 람다식이 생겼다.
람다식의 문법은 하나의 명령문을 가지고 있냐, 여러개를 가지고 있냐에 따라 다르다.
여러개의 명령문을 가지고 있는 경우
(인수 리스트) -> { 명령문1; 명령문2; retunr 값; }
하나의 명령문을 가지고 있는 경우
(인수 리스트) -> 명령문
위에 나온 리턴타입으로 사용된 인터페이스 사용방법 예시를 람다식으로 표현한다면 아래 예시처럼 나온다.
// 리턴타입으로 나온 인터페이스 /* public static Myinterface myMethod() { return new Myinterface(){ @Override public void print(){ System.out.println("hello"); } } } */ // 람다식으로 표현 public static void main(String[] args){ Myinterface m = () -> System.out.println("hello"); m.print(); }
위 예시처럼 람다식을 사용하려면 interface자체에 메소드가 두개 이상이 있으면 안되고 오직 한개만을 메소드로 가지고 있는 interface만 람다식으로 사용할 수 있다.
그렇기 때문에 @FunctionalInterface 어노테이션으로 인터페이스에 표시하면 람다식을 사용하기 더 편하다.
매개변수가 없는 경우
interface Myinterface(){ public void print(); } Myinterface m1 = () -> {System.out.println("Hi");} Myinterface m2 = () -> System.out.println("Hi"); m1.print(); m2.print();
매개변수가 있는 경우에는 매개변수 이름만 적고 람다식표현을 진행한다.
매개변수가 있는 경우
interface Myinterface1(){ public void print(String s1); } interface Myinterface2(){ public void print(String s1, String s2); } Myinterface1 m1 = (s1) -> System.out.println(s1); Myinterface1 m1 = s1-> System.out.println(s1); // ()괄호 생략가능 m1.print("Hello"); Myinterface2 m2 = (s1, s2) -> System.out.println(s1+":"+s2); m2.print("Seoul","Korea");
리턴 값이 없는 경우
interface Myinterface(){ public void print(); } Myinterface m1 = () -> {System.out.println("Hi");} m1.print();
리턴 값이 있는 경우
interface Myinterface(){ public String getMessage(); } Myinterface m = () -> { String message = "Hello"; return message; }
리턴 문 하나만 있는 경우
interface Myinterface(){ public int sum(x,y); } Myinterface m = (x,y) -> x+y; int r = m.sum(15,20); // 결과 : 35
람다식이 지역변수를 사용하기 위해서는 지역변수가 final 상수 여야 한다. 하지만, 메소드에서 인자로 넘어온 값을 람다식이 사용할때, 자바에서 그 값을 final상수 취급을 하기 때문에 사용가능하다.
interface Myinterface(){
public void print();
}
public class Test{
public void test(String s){
Myinterface m= () -> {
System.out.println(s);
};
m.print();
}
}
public static void main(String [] args){
Test t = new Test();
t.test("hello");
}
하지만 지역변수를 사용할때 수정을 한다면 에러가 난다.
interface Myinterface(){
public void print();
}
public class Test{
public void test(String s){
Myinterface m= () -> {
s = s.toUpperCase(); // 오류
System.out.println(s);
};
m.print();
}
}
public static void main(String [] args){
Test t = new Test();
t.test("hello");
}
멤버변수는 수정 가능 하다.
public class Test{
Strng name="홍길동";
public void test(String s){
Myinterface m= () -> {
name = name.toUpperCase(); // 오류
System.out.println(name);
};
m.print();
}
}
제공되는 api(java.util.function)중에서 람다식으로 표현할 수 있는 함수형 인터페이스는 간단한 코드로 여러가지 작업을 가능하게 한다.
인자값도 있고 리턴값도 받고자 할 때 사용하는 함수형 인터페이스다. apply()메소드를 가지고 있다.
public static void main(String[] args){
Function<String, Date> date = (s) ->{
Date d = null;
try{
d = new SimpleDateFormat("YY/MM/DD").parse(s);
}catch(ParseException e){
e.printStackTrace();
}
return d;
};
Date today = date.apply("2023/05/26");
System.out.println(today);
}
인수를 받고 boolean타입으로 리턴을 하는 함수형 인터페이스다. test()메소드를 가지고 있다.
public static void main(String[] args){ Predicate<String> check = (s) -> s.equals("java"); boolean result = check.test("java"); System.out.println(result); }
인수를 받지만, 리턴값이 없는 함수형 인터페이스다. accept()메소드를 가지고 있다.
public static void main(String[] args){
Consumer<Date> datePrint = (date) -> {
String s = new SimpleDateFormat("YY/MM/DD").format(date);
System.out.println(s);
};
datePrint.accept(new Date());
}
인수는 받지 않고 T타입의 값을 리턴받는 함수형 인터페이스다. get()메소드를 가지고 있다.
public static void main(String[] args){
Supplier<String> city = () -> {
String[] arr = {"서울","대구","대전","부산","인천"};
int index = (int)(Math.random()*5);
return arr[index];
};
String s = city.get();
System.out.println(s);
}