[Java] 자바 #45, 람다식 예제 및 활용

람다식(Lamda)

 - 병렬처리, 이벤트 처리, 스트림 처리 등..사용

 - JDK 1.8에서 지원.

 - 함수형 프로그래밍 방식( <-> 객체지향 프로그래밍)

 - 형태는 매개변수를 가지는 코드블럭(=메소드)

 - 인터페이스 + 익명객체 + 람다식 같이사용.

 - 생김새는 메소드를 선언하는 것과 유사 -> 실제로는 이름없는 클래스와 이름없는 메소드를 만드는 코드

 - (중요)람다식을 사용하는 이유는 1회용 익명 메소드가 필요하기 때문 > 하지만 자바는 독립적인 메소드만을 생성하지 못하기 때문에 익명객체를 이용해서 만든다.



1
2
3
4
5
6
7
interface MyInterface {
    void test();
}
 
interface MyType {
    void hello();
}
cs


위와 같은 인터페이스가 있을 때!


기본적인 익명객체를 이용해서 익명 메소드를 사용하는 방법


// 익명객체

MyInterface my1 = new MyInterface() { new 키워드로 객체 직접 대입

@Override

public void test() { 메소드까지 클래스에 기재하는 것처럼 선언 -> 비용심화

System.out.println("테스트 입니다.");

}

};

my1.test(); 메소드사용

MyType my2 = new MyType() {

@Override

public void hello() {

System.out.println("안녕하세요. 홍길동입니다.");

}

};

my2.hello(); 메소드사용


람다식을 이용해서 익명 메소드를 사용하는 방법


람다식 기본 형태

 - (자료형 매개변수) -> { 실행코드; }

  a. 매개변수 : 메소드 매개변수

  b. "->" : 에로우, 코드블럭을 실행(호출)

  c. "{ }" : 메소드 구현부


익명 메소드 -> 람다식을 사용해서 익명 메소드 생성


MyType my3 = () -> { 이런식으로 익명객체를 생성 후 그 안에 오버라이딩 메소드 내용을 기재

System.out.println("안녕하세요 아무개입니다.");

}; // 단일라인 메소드

my3.hello();


MyType my4 = (String message) -> { 

System.out.println("안녕하세요.");

System.out.println(message+"입니다.");

System.out.println("감사합니다.");

};

my4.hello("홍길동");


람다식의 간단한 표기 방법


1
2
3
interface YourType {
    void talk(String msg);
}

cs


위의 인터페이스를 예로 들면...

매개변수 1개 반환값 X


1. (int num) -> {System.out.println()};  가장 기본형태

ex) 

YourType you = (String name) -> { System.out.printf("내이름은 %s입니다.",name); }

you.talk("홍길동");


2. (int num) -> System.out.println(); 단일코드 -> 실행블럭 제거

ex)

YourType you = (String name) -> System.out.println(name);

you.talk("홍길동");


3. (num) -> System.out.println(); 단일 매개변수 -> 타입 생략 -> 변수명만 기재

ex)

YourType you = (name) -> System.out.println(name);

you.talk("홍길동");


4. num -> System.out.println(); 매개변수가 1개일때는 매개변수를 감싸는 괄호 생략가능

ex)

YourType you = name -> System.out.println(name);

you.talk("홍길동");


1
2
3
interface MyType {
    void hello();
}
cs

- 매개변수 X, 반환값 X


5. () -> System.out.println(); 매개변수가 없는 람다식 -> 괄호를 무조건 기재

ex)

MyType my = () -> System.out.println("이거로 뭘할수있을까...");


1
2
3
interface MyType {
    void hello(String name, int age);
}
cs

- 매개변수 2개, 반환값 X


6. (x,y) -> System.out.println(); 매개변수가 여러개 일때 -> 괄호로 무조건 감싸야함

ex)

MyType my = (name, age) -> System.out.printf("내 이름은 %s이고 %d살이야"); 

my.hello("홍길동",19);


1
2
3
interface HisType {
    String getFood();
}
cs

- 매개변수 X, 반환값 O

7. () -> {return value;} 물론 단일코드이기 때문에 괄호도 생략 가능

ex)

HisType his = () -> return "food";

System.out.println( his.getFood() );


8. () -> value; return문만 있는 단일코드는 return과 괄호를 같이 생략 가능

ex)

HisType his = () -> "food";

System.out.println( his.getFood() );


1
2
3
interface HisTpye {
    String sayHello(String name, int age);
}
cs

9. (x,y) -> x+y; 매개변수 2개 이상, 반환타입 O, 리턴문 단일코드

ex)

HisType his = ( name, age ) -> String.format("안녕하세요. 제이름은 %s이고 %d살 입니다.",name, age);

System.out.println(his.sayHello("홍길동",19));



람다식을 이용한 정렬메소드 구현


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
class User {
    private String name;
    private int age;
 
    public User() {
 
    }
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return String.format("%s(%s)"this.name, this.age);
    }
}
cs


- 위와 같은 User 클래스가 있을 때

- List 컬렉션에 User객체를 5개 담아보았다. 


List<User> list = new ArrayList<User>();


list.add(new User("홍길동", 20));

list.add(new User("아무개", 25));

list.add(new User("무지개", 21));

list.add(new User("김린지", 24));

list.add(new User("호호호", 29));


System.out.println(list); 그냥 출력 결과 : [홍길동(20), 아무개(25), 무지개(21), 김린지(24), 호호호(29)] 


나이순 정렬을 하고 싶다. -> Collections.sort()와 Arrays.sort()는 이용할 수 없음.

->Comparator 객체를 이용해 구현.


list.sort(new Comparator<User>() {

@Override

public int compare(User o1, User o2) {

return o1.getAge() - o2.getAge(); // 정렬기준. -> 앞에 매개변수 - 뒤의매개변수 -> 오름차순

}

});

System.out.println(list); [홍길동(20), 무지개(21), 김린지(24), 아무개(25), 호호호(29)]


이것을 람다식으로 구현하면 다음과 같다.


람다식 구현(나이기준)

list.sort((o1, o2) -> o2.getAge() - o1.getAge()); //코드량이 현저히 줄었다.(이건 내림차순이다.)

System.out.println(list); [호호호(29), 아무개(25), 김린지(24), 무지개(21), 홍길동(20)]



그렇다면 이름기준으로 정렬은 못하나...? -> X 할수 있다! -> TreeSet을 이용.


TreeSet<User> set = new TreeSet<User>((o1,o2)-> o1.getName().compareTo(o2.getName()));

- TreeSet 타입이 User인 참조타입이므로 기준을 잡기가 힘듬. -> 기준을 잡아주는 작업 -> compareTo 메소드 활용.

set.add(new User("홍길동", 20));

set.add(new User("아무개", 25));

set.add(new User("무지개", 21));

set.add(new User("김린지", 24));

set.add(new User("호호호", 29));

System.out.println(set);  [김린지(24), 무지개(21), 아무개(25), 호호호(29), 홍길동(20)]


- compareTo는 String 타입 전용이므로 다시 나이순으로 정렬하기 위한 조건은 위의 람다식으로 쓴 익명객체를 TreeSet생성자 안에 넣어주면 된다.

- TreeSet<User> set = new TreeSet<User>((o1,o2)-> o1.getAge() - o2.getAge()));


람다식 실제 사용

- 인터페이스 변수 = 람다식;

- 람다식과 인터페이스는 밀접한 관계(람다식 시그너처 == 인터페이스 추상메소드의 시그너처)

람다식에서 사용되는 인터페이스

1. 반드시 추상메소드가 유일해야 한다.(*****)

2. 람다식을 담는 인터페이스를 주로 타겟 타입(Target Type)이라고 한다.

3. 람다식을 담는 인터페이스를 주로'함수적(형) 인터페이스, Functional Interface 라고 한다.

4. 자바는 개발자에 사용하기 위한 함수적 인터페이스를 여러개 제공합니다.






댓글

Designed by JB FACTORY