About Me/인프런 워밍업 클럽

[인프런 워밍업 클럽 1기] BE 3일차 과제

블로그 주인장 2024. 5. 2.

BE 3일차 과제

인프런 워밍업 클럽 1기 BE 3일차 과제에 대해 살펴보겠습니다.

자바에서 익명클래스와 람다식이 등장한 배경부터 기능적 차이점, 그리고 이들이 어떤 방식으로

함수형 프로그래밍을 이끌어가고 있는지 알아보려고 합니다.

 

 

람다식이란?

람다식(Lambda Expressions) 이란 간단히 말해 메서드를 하나의 식(expression)으로 표현한 것입니다.

 

즉, 코드를 더욱 간결하고 명료하게 만들어주면서, 

Java 8부터 등장하여 함수형 프로그래밍의 패러다임을 자바 언어에 도입했습니다.

 

 

아래의 코드 예시를 보면서 설명하겠습니다.

리스트에 인덱스를 넣고 해당 리스트의 인덱스를 출력하는 코드입니다.

 

람다식의 기본 형태는 (매개변수 -> {실행 코드}) 입니다.

즉, item 이라는 매개변수를 System.out.Println  출력을 실행하겠다는 것을 알 수 있습니다.

import java.util.Arrays;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("사과", "바나나", "체리", "딸기");
        list.forEach((String item) -> System.out.println(item));
    }
}

 

 

람다식의 등장 배경

일찍이 자바에서는 익명 클래스를 사용하여 코드의 간결성을 제공하려고 했습니다.

 

여기서 말하는 익명 클래스는 이름이 없는 클래스로, 주로 인터페이스의 구현이나 추상 클래스의 확장에 사용됩니다.

 

아래의 코드 예시를 보면서 설명하겠습니다.

 

Comparator 인터페이스를 활용해서 문자열의 길이에 따라 정렬하는 익명 클래스를 구현한 내용입니다.

Comparator는 자바의 함수형 인터페이스 중 하나로써, 2개의 객체를 비교하는 데 사용됩니다.

import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        String[] fruits = {"Apple", "Orange", "Banana", "Lemon"};

        Arrays.sort(fruits, new Comparator<String>() {
            @Override
            public int compare(String fruit1, String fruit2) {
                return Integer.compare(fruit1.length(), fruit2.length());
            }
        });

        System.out.println(Arrays.toString(fruits));
    }
}

 

위의 코드에서 Arrays.sort 메서드는 두 번째 매개변수로 익명 클래스가 사용되었습니다.

 

해당 익명 클래스는 Comparator<String> 인터페이스를 구현합니다.

구현된 compare 메서드는 두 문자열(두 과일 이름)의 길이를 비교하여 정렬 기준을 제공합니다.

 

익명 클래스는 특정 기능(문자열 길이에 따른 비교)를 수행하는 compare 메서드만을 목적으로 하는 임시 구현체를 생성합니다.

 

익명 클래스의 사용으로 인해, 추가적인 외부 클래스를 정의하지 않고도 바로 필요한 기능을 구현하고 사용할 수 있습니다.

 

하지만, 코드가 길어지고 복잡해지는 단점이 있었습니다.

 

개발자들은 이러한 문제점들을 해결하고자 람다식을 도입했으며, 이는 함수형 프로그래밍의 접근을 가능케했습니다.

 

 

함수적 인터페이스(@FunctionalInterface)

람다식은 사실 익명 클래스의 개선된 형태라고 볼 수 있습니다.

 

익명 클래스와 마찬가지로 람다식도 함수적 인터페이스(@FuntionalInteface)의 인스턴스를 쉽게 생성할 수 있게 해줍니다.

 

위에서 말하는 함수적 인터페이스란 오직 하나의 추상 메서드만 가지고 있는 인터페이스를 뜻합니다.

 

아래의 예시처럼 @FunctionalInterface 어노테이션을 붙여서 함수적 인터페이스 임을 명시적으로 나타낼 수 있습니다.

이를 통해 람다식을 사용하거나 메서드 참조를 할 때 유용하게 사용할 수 있습니다.

 

StringProcessor 는 하나의 추상 메서드 process를 가진 함수적 인터페이스입니다.

이 인터페이스는 문자열을 받아서 처리하고 문자열을 반환하는 함수를 정의합니다.

@FunctionalInterface
public interface StringProcessor {
    String process(String str);
}

 

위의 인터페이스를 사용한 예시를 보겠습니다.

 

문자열을 뒤집는 람다식을 사용하여 StringProcessor 인터페이스를 구현합니다.

그리고 구현된 process 메서드를 사용하여 문자열 "Hello"를 뒤집어 "Olleh"로 출력할 수 있습니다.

public class Example {
    public static void main(String[] args) {
        // 람다식을 사용한 StringProcessor 인터페이스의 구현
        StringProcessor reverse = s -> new StringBuilder(s).reverse().toString();
        
        // 구현된 인터페이스의 메소드 사용
        String result = reverse.process("hello");
        System.out.println(result); // "olleh"
    }
}

 

즉, 함수형 인터페이스는 자바에서 보다 쉽고 깔끔하게 작성할 수 있게 해줍니다.

@FunctionalInterface 어노테이션을 사용함으로써 해당 인터페이스가 하나의 추상 메서드만을 가지고 있음을

컴파일러에게 명시적으로 알려줄 수 있으며, 이는 코드의 명확성과 안정성을 높여줍니다.

 

 

자바의 함수형 프로그래밍

람다식의 도입은 자바에서의 함수형 프로그래밍을 본격화하는 계기가 되었습니다.

 

스트림 API메서드 레퍼런스(Method Reference)는 이러한 패러다임의 전환을 더욱 강력하게 지원합니다.

 

스트림 API를 사용하면 컬렉션 데이터(List, Map, Set) 를 선언적으로 처리할 수 있습니다.

 

아래의 코드 예시를 보면서 설명하겠습니다.

 

1 ~ 10 까지의 정수의 인덱스가 있는 numbers 라는 리스트를 생성했습니다.

자바의 스트림 API와 결합하여 짝수만 필터링을 할 수 있도록 구현한 내용입니다.

 

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Example {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        List<Integer> evenNumbers = numbers.stream()
                                           .filter(n -> n % 2 == 0)
                                           .collect(Collectors.toList());
        System.out.println(evenNumbers);
    }
}

 

해당 코드는 여러 단계를 거쳐 처리가 수행됩니다.

 

1. numbers.stream()으로 리스트로부터 스트림을 생성합니다.

2. filter(n -> n % 2 == 0) 로 짝수만을 필터링합니다.

3. collect(Collectors.toList()) 로 스트림의 결과를 새로운 리스트로 수집합니다.

 

결과로 evenNumbers 리스트에는 원본 리스트 numbers에 있는 짝수의 값으로 채워집니다.

 

스트림 API를 활용하면 몇 줄 안되는 코드로 컬렉션을 효과적으로 처리할 수 있으며

코드의 가독성과 유지 보수성이 향상되는 것을 알 수 있습니다.

 

 

또한, 메서드 레퍼런스는 람다식을 더욱 간결하게 만들어줍니다.

 

메서드 레퍼런스는 특정 메서드만 호출하는 람다 표현식을 한 단계 더욱 단순화시킵니다.

 

아래의 예시는 문자열의 리스트를 대소문자 구분 없이 정렬하는 코드입니다.

 

String의 compareToIgnoreCase 메서드를 사용하여 대소문자 구분 없이 문자열을 비교하는 방법입니다.

위의 메서드를 기반으로 List의 sort 메서드를 사용할 때 메서드 레퍼런스를 사용할 수 있습니다.

 

String::compareToIgnoreCase 는 각 요소(문자열)의 compareToIgnoreCase 메서드를 참조하여 정렬 기준을 제공합니다.

람다식으로 표현한다면 (s1, s2 -> s1. compareToIgnoreCase(s2))와 같습니다.

import java.util.Arrays;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("Banana", "apple", "Orange", "lemon");
        
        // 메서드 레퍼런스를 사용하여 대소문자 구분 없이 리스트 정렬
        fruits.sort(String::compareToIgnoreCase);
        
        // 정렬된 리스트 출력
        System.out.println(fruits);
    }
}

 

즉, 메서드 레퍼런스는 코드를 보다 명확하고 간결하게 표현할 수 있습니다.

특히, 함수형 인터페이스를 구현할 때 유용하다고 볼 수 있습니다.

 

마무리

자바의 함수형 프로그래밍 접근법은 코드를 더욱 간결하고 효율적으로 만드는 데 큰 역할을 하고 있습니다.

람다식 및 함수형 프로그래밍을 이해하고 잘 활용한다면, 자바에 대한 이해와 프로그래밍 실력을 늘릴 수 있을 거 같습니다.

 

 

Reference

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

 

 

본 포스트는 작성자가 공부한 내용을 바탕으로 작성한 글입니다.
잘못된 내용이 있을 시 언제든 댓글로 피드백 부탁드리겠습니다.
항상 정확한 내용을 포스팅하도록 노력하겠습니다.

반응형

댓글