Java - 람다 표현식(lamda Expression)

 

Java 8부터 사용할 수 있는 람다(lamda) 표현식은 주로 함수형 인터페이스를 구현하는데 사용된다.

 

 예를 들면 아래와 같이 람다를 활용하면 별도의 클래스를 작성하지 않고 일회성으로  

Runnable 인터페이스의 기본적인 함수인 run() 메소드를 오버라이딩하여 일회용 구현체(?) 같은 느낌으로 작성할 수 있다.

1. 람다 표현식을 활용한 인터페이스 메소드 구현

Runnable runnable = () - > System.out.println(" I'm running in a Thread ");
new Thread(runnable).start();

 

2. 람다 표현식을 활용한 리스트 정렬

List<String> names = Arrays.asList("mimi", "nanan", "BBo");
names.sort(Comparator.naturalOrder());
names.forEach(System.out::println);

 

3. 람다 표현식 + Stream을 활용한 리스트 데이터 처리

List<Integer> numbers = Arrays.asList(1,2,3,4,5);

numbers.stream()
    .filter(n -> n % 2 ==0)
    .forEach(System.out::println);

 

 

✅ 확장 예제 1: 스트림에서 예외 처리하기

🔹 상황

파일에서 숫자를 읽어 리스트로 만든 후, 각 숫자를 정수로 파싱하여 제곱값을 출력하려고 한다.

하지만 문자열이 숫자가 아닐 경우 예외가 발생할 수 있다.

List<String> inputs = Arrays.asList("10", "20", "a", "30");

inputs.stream()
    .map(input -> {
        try {
            return Integer.parseInt(input);
        } catch (NumberFormatException e) {
            System.err.println("Invalid input: " + input);
            return null;
        }
    })
    .filter(Objects::nonNull)
    .map(n -> n * n)
    .forEach(System.out::println);

🔹 포인트

  • 람다 내부에서 try-catch 사용 가능
  • null 필터링을 통해 유효한 값만 처리

 

✅ 확장 예제 2: 병렬 스트림 (Parallel Stream)

🔹 상황

대규모 데이터 집합에 대해 연산을 빠르게 처리하고자 할 때, 멀티코어를 활용한 병렬 처리.

 

🔹 코드

List<Integer> numbers = IntStream.rangeClosed(1, 1000000)
                                 .boxed()
                                 .collect(Collectors.toList());

long start = System.currentTimeMillis();

int sum = numbers.parallelStream()
                 .filter(n -> n % 2 == 0)
                 .mapToInt(n -> n)
                 .sum();

long end = System.currentTimeMillis();

System.out.println("Sum of evens: " + sum);
System.out.println("Time taken: " + (end - start) + "ms");

 

🔹 포인트

  • .parallelStream() 사용 시 멀티코어 자동 활용
  • CPU-bound 작업일수록 효과 큼 (I/O 작업에는 부적절할 수 있음)

 

💡(알면좋고) CPU-bound란?

CPU-bound 작업이란, 프로그램이 CPU 연산 능력에 크게 의존하는 작업을 말한다.
즉, 컴퓨터의 계산 처리 속도가 작업의 병목(bottleneck)이 되는 경우이다.

CPU-bound CPU의 연산 능력이 제한 요인 - 수학 계산- 해시 암호화- 영상 인코딩- 데이터 압축
I/O-bound 디스크, 네트워크 같은 입출력 속도가 병목 - 파일 읽기/쓰기- DB 쿼리- API 요청- 사용자 입력 대기



 

✅ 확장 예제 3: 중첩 필터와 정렬, 매핑 조합

🔹 상황

고객 리스트에서 20세 이상이며 이름에 "김"이 포함된 사람만 추려 이름을 가나다 순으로 정렬 후 대문자로 출력

 

🔹 코드

class Customer {
    String name;
    int age;
    public Customer(String name, int age) {
        this.name = name; this.age = age;
    }
    public String getName() { return name; }
    public int getAge() { return age; }
}

List<Customer> customers = Arrays.asList(
    new Customer("김철수", 25),
    new Customer("홍길동", 30),
    new Customer("이영희", 19),
    new Customer("김민정", 22)
);

customers.stream()
         .filter(c -> c.getAge() >= 20)
         .filter(c -> c.getName().contains("김"))
         .sorted(Comparator.comparing(Customer::getName))
         .map(c -> c.getName().toUpperCase())
         .forEach(System.out::println);

 

🔹 포인트

  • filter 두 번 사용 가능 (조건 나눠서 처리 가능)
  • Comparator.comparing()으로 정렬
  • map으로 객체에서 이름 추출 후 대문자 변환