< Java > lamda
lamda 란?
람다 함수는 말 그대로 함수(function) 이다.
(메서드가 아니라는 뜻)
이 함수는 자바 스크립트에서 파급되었고, 요즘은 거의 모든 언어에서 사용한다.
익명 메서드를 구현하는 형태라고 생각하면 편하다.
익명객체 이름이 없는 객체를 뜻하듯이 함수명이 없이 선언된 함수와 특정 데이터 영역을 이 함수를 통해서
구현하게끔 하는 형태이다.
자바에서도 람다를 지원하는데, 규칙이 매우 엄격합니다.
아래는 람다 표현식에 규칙입니다.
- 모든 람다 함수는 인터페이스만 가능하다.
- 람다 함수가 되는 함수를 가진 인터페이스는 무조건 람다 함수 하나만 보유해야합니다.(반드시)
- 람다 함수는 인터페이스에서 선언되었기 때문에, 당연히 body 가 없습니다. 따라서 구현 시에 body를 추가합니다.
- FunctionInterface 라는 어노테이션을 인터페이스 선언문 전에 선언해서 람다 인터페이스임을 선언해야합니다.
만약 안하면 컴파일 시 위 조건을 컴파일러가 검색해서, 문제 없으면 자동으로 넣어 줍니다. - JDK1.8부터는 인터페이스에서 static 메서드를 이용해서 메서드 boby 를 질 수 있고
default 키워드를 통해서 기본 메서드 또한 가질 수 있습니다.
즉 위 예를 종합하면, 람다 인터페이스는 총 3개의 메서드를 보유할 수 있는데, 위 두개와 람다 하나입니다.
더이상 보유하게 되면 컴파일 에러가 발생합니다.
문법
(파라미터 1, 2,,,, n ) -> { 파라미터 처리식 }
System.out::println ( 메서드 람다식 )
위 문법에서 파라미터가 하나도 없을 경우엔 () 처리한다.
그리고 구현하는 로직이 있는 경우엔 -> 를 통해 {구현로직} 을 정의한다라고 선언하는 방식입니다.
여기서 -> 는 반드시 넣어야하며
저는 -> 를 메서드 명 이라고 생각하니깐 쉽게 이해 됩니다.
a + b 결과값을 받아서 다음 로직에서 처리를 해야 한다면??
int sum(int a, int b) { return a+b}
(a,b) -> {a + b}
- 파라미터가 하나만 필요한 경우
하나일 경우에는 괄호를 생략해도 됨
만약 구현부가 하나의 수행문인 경우엔 {} 도 생략 가능함.
a -> {return a == 0 ? a : 1}
a -> return a == 0 ? a : 1
파라미터가 없을 경우 : () -> {} 처럼 빈 괄호를 이용해야 한다.
즉 파라미터 위치값은 반드시 존재해야 한다는 것입니다.
class MyRun implements Runnable {
@Override
public void run() {
System.out.println("runnable thread run");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end of runnable thread ");
}
}
public class LamdaEx1 {
public static void main(String[] args) {
Thread t = new Thread(); // 빈 스레드 { run이 없으니깐 아무것도 안 함}
// Runnable 객체를 파람으로 받는 스레드 객체를 생성.
Thread runnableT = new Thread(new MyRun());
runnableT.start();
Thread anonyT = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("anoy runnable thread run");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end of anoy runnable thread ");
}
});
anonyT.start();
// Lamda 로 정의
Thread lam = new Thread(() -> {
System.out.println("Lamda runnable thread run");
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("end of Lamda runnable thread ");
});
lam.start();
}
list.foreach 람다식
기존 list 요소 뽑아내기
public class LamdaEx2 {
public static void main(String[] args) {
ArrayList<Integer> l1 = new ArrayList();
l1.add(1);
l1.add(2);
l1.add(3);
// 1번 방법
System.out.println("-----------------------");
for (int i = 0; i < l1.size(); i++) {
System.out.println(l1.get(i));
}
//2번 방법
System.out.println("-----------------------");
for (Integer i : l1) {
System.out.println(i);
}
람다 lists.foreach
foreach 를 이용한 람다 함수 적용방법
stream 객체의 메서드를 이용한 형태
stream 객체는 쉽게 표현하자면 다중 스레드를 내부적으로 병렬로 CPU 를 가동하도록 정의된 데이터 스트림입니다,
IO 와는 완전 다른 개념
public class LamdaEx2 {
public static void main(String[] args) {
ArrayList<Integer> l1 = new ArrayList();
l1.add(1);
l1.add(2);
l1.add(3);
// foreach 를 이용한 람다 함수 적용 방법
System.out.println("-----------------------");
l1.forEach(t -> {
System.out.println(t);
});
System.out.println("-----------------------");
l1.forEach(System.out::println); // 또다른 람다식
@FunctionalInterface 의 추상 메서드를 람다 함수로 가져다 쓰기
람다 함수는 특정 데이터가 있을 때 특정 기능의 함수를 그때그때 적용해서 결과를 도출하기 위한 목적입니다.
import java.util.ArrayList;
@FunctionalInterface
interface MyInter{
default void sum1() {
System.out.println("이건 jdk 1.8 ?? 부터 지원되는 인턴페이스의 기본 메서드 입니다.");
}
// 아래는 static 메서드
// 1.8 부터 지원되는 메서드
static int sum2() {
return 100;
}
// 하위는 람다 함수로 사용할 메서드, 반드시 추상이어야 한다.
public int sum3(int a, int b);
}
public class LamdaEx2 {
public static void main(String[] args) {
MyInter function = (x,y) ->x + y;
System.out.println(function.sum3(3, 2));
}
public int sum3(int a, int b);
@FunctionalInterface 를 이용하면 해당 interface 에 추상메서드로 선언된 메서드는 자동으로 람다 함수로 적용된다
그리고 만약에 추상메서드가 하나 이상으로 정의된다면 그것은 바로 컴파일 에러가 뜨는 것을 확인 할 수 있었다.
위에 적었듯이 자바의 람다함수는 엄격한 규칙을 가지고 있기때문에 위에 적은 규칙을 주의하여 이용해야겠다.