AWS BACK DAY 21. 람다(Lambda)

이강용·2023년 1월 31일

Java 기초

목록 보기
19/26

📌람다(Lambda)

  • 람다 표현식(Lambda Expression)이란 선언없이 실행 가능한 method이다.
  • 간단히 말해, 코드 한줄에 메서드를 써서 그것을 호출하는 방식으로 표현한 것

장점(Lambda)

  • 불필요한 코드를 제거하여 코드를 간결하게 만들 수 있음
  • 코드가 간결하고 개발자의 의도가 명확히 드러나므로 가독성이 향상됨
  • 메서드를 만드는 과정없이 일괄 처리할 수 있기에 코딩 시간이 단축됨
  • 다중 CPU를 활용하는 형태로 구현되어 병렬 처리에 유리

단점(Lambda)

  • 람다를 사용하면서 만드는 익명클래스(Anonymous class)는 재사용이 불가능함
  • 디버깅 시 메서드 콜 스택 추적이 다소 어려움
  • 재귀함수로 만들어 완전탐색을 하는 경우 실행 속도가 느릴 수 있음
  • 한 클래스내에 많은 람다식을 사용하는 경우, 오히려 가독성이 떨어짐

📌람다(Lamdba)의 사용법

  • Java에서는 화살표 (->) 기호를 사용하여 매개변수부선언부로 나눔
//(argument) -> {body} 구문을 사용하여 작성
  (    )  -> {/* 함수 코드 작성 */}
  • 람다식 사용을 위해서는, 함수형 인터페이스(Functional Interface)에 접근하여 사용
    • 함수형 인터페이스란 한개의 abstract method를 가지는 인터페이스로, 동적 메서드 구현 후 사용하기 위해 정의
  • 매개변수의 (자료형)타입을 추론할 수 있는 경우 (자료형)타입을 생략할 수 있음
  • 매개변수 작성부에서 변수가 하나인 경우에는 괄호()를 생략할 수 있음
  • 메서드의 몸체(Body)가 하나의 명령문만으로 구성된 경우 중괄호{}를 생략할 수 있음
    • ❗ 세미콜론;은 붙이지 않음
  • 메서드의 몸체에 return문이 있는 경우 중괄호{}는 생략할 수 없음
  • return문 대신 표현식을 사용할 수 있으며, 반환값은 표현식의 결과값이 된다
    • ❗ 세미콜론;은 붙이지 않음

📑 기본 함수형 인터페이스

함수형 인터페이스메서드매개변수반환값
java.lang.Runnablevoid run()
Supplier < T >T get()
Consumer < T >void accept(T t)
Function< T, R >R apply(T t)
Predicate < T >boolean test(T t)
  • Instrument Interface
@FunctionalInterface //람다 (중복 정의를 막아주는 어노테이션)

public interface Instrumnet {

	public String play(String instrument);
			
}
  • main

  • Interface method에 접근하여 람다식 사용

public class Lambda1 {
	
	public static void main(String[] args) {
	
		Instrumnet it = new Instrumnet() {
			
			@Override
			public String play(String instrument) {  // 구현부 (일회용 클래스)
				

				return instrument + "을(를) 연주합니다.";
			}
		};
		System.out.println(it.play("피아노"));	
	}
}
  • 람다 전 (before) ↔ 람다 후 (after)
Instrumnet it = new Instrumnet() {
			
			@Override
			public String play(String instrument) {  // 구현부 (일회용 클래스)
				

				return instrument + "을(를) 연주합니다.";
			}
		};
Instrumnet it2 = (String itm) -> {
			
			return itm + "을(를) 연주합니다 ";
		};
        
		String playText = it2.play("드럼"); 
		System.out.println(playText);        

최종 형태

Instrumnet it6 = itm -> itm + "을(를) 연주합니다 " ;
  • 매개변수의 자료형 생략
  • 매개변수명을 바꿈
		Instrumnet it3 = (itm) -> {
			
			return itm + "을(를) 연주합니다 ";
		};
  • 매개 변수가 하나면 괄호를 생략
		Instrumnet it4 = itm -> {
			
			return itm + "을(를) 연주합니다 ";
		};

📌 1. Runnable - run()

public class Lamdba2 {
	
	
	public static void main(String[] args) {
		
		// 1. Runnable - run()
		
		Runnable a = () -> System.out.println("실행");
		Runnable b = () -> {
			System.out.println("여");
			System.out.println("러");
			System.out.println("명");
			System.out.println("령");
			System.out.println("실");
			System.out.println("행");
		
		};
		a.run();
		b.run();
	}

}

📌2. Supplier< T > - T get()

Supplier<LocalDate> c = () -> LocalDate.now();
		Supplier<String> d  = () -> {
			LocalDate now = LocalDate.now();
			return now.format(DateTimeFormatter.ofPattern("yyyy년 MM월 dd일"));
            // 소문자 y (년) , 대문자 M (월) , 소문자 d (일)
			
		};
		
		System.out.println(c.get());
		System.out.println(d.get());

📌3. Consumer< T > - void accept(T t)

Consumer<String> e = name -> {
			System.out.println("이름: " + name);
			System.out.println("오늘 날짜: " + d.get());
		};
		e.accept("홍길동");

method 참조 표현식

// 메서드 참조 표현식 ( [인스턴스] :: [메서드명 또는 new])
		Consumer<String> f = System.out::println;
		f.accept("출력");
List<String> names = new ArrayList<>();
		names.add("김동민");
		names.add("김두두");
		names.add("장진원");
		names.add("조병철");
        
		// #1
        Consumer< String > g = name -> System.out.println("이름: " + name + "님");
		names.forEach(g);
        /////////////////////// 또 다른 방법 //////////////////////////
        // #2
        names.forEach(name -> System.out.println("이름: " + name + "님"));
        

📌forEach

names.forEach(name -> {
		System.out.println("이름을 출력합니다.");
		System.out.println("이름: " + name);
		System.out.println();
		});
Map<String, String> userMap = new HashMap<>();
		userMap.put("username","aaa");
		userMap.put("password","1234");

구현의 두 가지 방법

for(Entry<String,String> entry : userMap.entrySet()){
		 System.out.println("key: " + key);
	     System.out.println("value: " + value);
		 System.out.println();
		}

세련된 방법

userMap.forEach((key,value) ->{
			System.out.println("key: " + key);
			System.out.println("value: " + value);
			System.out.println();
		});

📌4. Function < T , R >

  • 매개변수 ○, 반환값 ○
Function<String, Integer> h = num -> Integer.parseInt(num);
		int convertStrNum1 = h.apply("100000");
		int convertStrNum2 = h.apply("200000");
		
		System.out.println(convertStrNum1+convertStrNum2);

📌5. Predicate < T >

  • 매개변수 ○, 반환값 ○ Function과 달리 Boolean 값을 반환
Predicate<String> p = str -> str.startsWith("김");
		Predicate<String> p2 = str -> str.startsWith("이");
		
		System.out.println(p.or(p2).test("김준일"));
Function<Predicate<String>, Boolean> function1 = 
				predicate -> predicate.or(str -> str.startsWith("이")).test("김준일"); 
		
		
		boolean rs = function1.apply(str -> str.startsWith("김"));
		System.out.println(rs);

번외) Stream

	// 스트림 -> 일회용
		Stream<String> stream = nameList.stream().filter(name -> name.startsWith("김"));
		//stream.forEach(name -> System.out.println(name));
		List<String> newList = stream.collect(Collectors.toList());
		newList.forEach(str -> System.out.println(str));
    // 한줄로 표현
    nameList.stream()
			.filter(name -> name.startsWith("김"))
			.collect(Collectors.toList())
			.forEach(System.out::println);
		  //.forEach(name -> System.out.println(name)); //똑같음
    

번외) 메서드 참조

  • 메서드 참조란 함수형 인터페이스를 람다식이 아닌 일반 메서드를 참조시켜 선언하는 방법
  • 일반 메서드를 참조하기 위해서는 3가지의 조건을 만족해야 한다.
    • 함수형 인터페이스의 매개변수 타입 = 메서드의 매개변수 타입
    • 함수형 인터페이스의 매개변수 개수 = 메서드의 매개변수 개수
    • 함수형 인터페이스의 반환형 = 메서드의 반환형
  • 참조 가능한 메서드는 일반 메서드, Static 메서드, 생성자가 있으며 클래스이름 :: 메서드 이름으로 참조할 수 있다. 이렇게 참조하면 함수형 인터페이스로 반환된다
profile
HW + SW = 1

0개의 댓글