JAVA

JAVA8 | 인터페이스 디폴트 메서드, Optional 클래스

TECH 톡마스터 2023. 6. 16.

JAVA8 | 인터페이스 디폴트 메서드, Optional 클래스
JAVA8 인터페이스 디폴트 메서드, Optional 클래스

 안녕하세요. 자바 개발은 끊임없는 발전과 혁신을 이뤄왔습니다. 그중에서도 자바 8은 많은 개선 사항과 새로운 기능들을 도입하여 개발자들에게 더 나은 개발 경험을 선사했습니다. 그중에서도 인터페이스 디폴트 메서드와 Optional 클래스는 자바 개발의 편의성과 효율성을 높여주는 친구들입니다. 인터페이스 디폴트 메서드를 통해 기존 인터페이스를 확장하고, Optional 클래스를 사용하여 예외 처리를 깔끔하게 해결할 수 있습니다. 자세히 알아볼까요?

1. 인터페이스 디폴트 메서드

1.1 디폴트 메서드가 뭔가요?

인터페이스 디폴트 메서드는 자바 8에서 도입된 개념으로, 기존의 인터페이스를 수정하지 않고도 새로운 기능을 추가할 수 있는 기능입니다. 이를 통해 기존에 인터페이스를 구현하는 클래스들에게 영향을 주지 않고 새로운 기능을 제공할 수 있습니다. 디폴트 메서드는 인터페이스 내부에서 구현되는 메서드로, 메서드의 시그니처와 기본 구현을 포함합니다. 디폴트 메서드는 "default" 키워드를 사용하여 정의되며, 구현체가 없는 메서드이기 때문에 인터페이스를 직접 인스턴스화할 수는 없습니다.

1.2 디폴트 메서드의 장점과 활용법

디폴트 메서드의 주요 장점은 다음과 같습니다

  • 기본 구현 제공 : 디폴트 메서드는 인터페이스 내에서 기본적인 구현을 제공합니다. 이는 해당 인터페이스를 구현하는 클래스가 디폴트 메서드를 오버라이딩하지 않아도 되는 이점을 제공합니다. 예를 들어, List 인터페이스에는 forEach라는 디폴트 메서드가 있어서 리스트의 요소를 각각 처리하는 기능을 제공합니다.
  • 인터페이스의 확장 : 디폴트 메서드를 통해 기존의 인터페이스를 확장하여 새로운 기능을 추가할 수 있습니다. 이는 인터페이스를 수정하지 않고도 호환성을 유지하면서 기능을 확장하는 데 도움을 줍니다.
  • 다중 상속 문제 해결 : 디폴트 메서드는 다중 상속 시 충돌 문제를 해결하기 위한 방법으로 도입되었습니다. 만약 여러 인터페이스에서 동일한 메서드 시그니처를 가지는 디폴트 메서드를 제공하면, 해당 인터페이스를 구현하는 클래스에서는 명시적으로 오버라이딩하여 충돌을 해결해야 합니다.

1.3 다중 상속 문제 해결

 디폴트 메서드의 가장 큰 장점 중 하나는 다중 상속 시 발생할 수 있는 문제를 해결할 수 있다는 점입니다. 예를 들어, 두 개의 인터페이스 A와 B가 있고, 두 인터 페이스 모두에 같은 시그니처를 가진 메서드가 있는 경우를 생각해 봅시다. 이때, 이 두 인터페이스를 구현하는 클래스 C가 있다면, 어떤 메서드를 선택해야 할까요? 자바 8 이전까지는 이런 다중 상속 문제를 해결하기 위해 클래스 C에서 해당 메서드를 직접 구현해야 했습니다. 하지만 자바 8에서는 디폴트 메서드를 활용하여 이 문제를 깔끔하게 해결할 수 있습니다.

이제 예제 코드를 통해 디폴트 메서드의 활용을 살펴보겠습니다.

interface Vehicle {
    void start();

    default void honk() {
        System.out.println("빵빵!");
    }
}

class Car implements Vehicle {
    @Override
    public void start() {
        System.out.println("자동차 출발!");
    }
}

class Bike implements Vehicle {
    @Override
    public void start() {
        System.out.println("자전거 출발!");
    }

    @Override
    public void honk() {
        System.out.println("따르릉!");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle car = new Car();
        car.start();  // 출력: 자동차 출발!
        car.honk();   // 출력: 빵빵!

        Vehicle bike = new Bike();
        bike.start(); // 출력: 자전거 출발!
        bike.honk();  // 출력: 따르릉!
    }
}

 위의 예제 코드에서는 Vehicle 인터페이스에 start() 메서드와 디폴트 메서드인 honk()를 정의했습니다. Car 클래스는 Vehicle 인터페이스를 구현하며, start() 메서드를 구현하고 디폴트로 제공되는 honk() 메서드를 사용합니다. Bike 클래스도 Vehicle 인터페이스를 구현하지만, honk() 메서드를 오버라이딩하여 자신만의 동작을 구현했습니다.

 Main 클래스에서는 Car와 Bike 객체를 생성하여 start()와 honk() 메서드를 호출합니다. 결과적으로 Car는 honk() 메서드를 디폴트 구현을 사용하고, Bike는 직접 오버라이딩한 구현을 사용하는 것을 볼 수 있습니다.

이렇듯 디폴트 메서드는 인터페이스의 기능을 유연하게 확장하고, 다중 상속 시 발생할 수 있는 충돌 문제를 해결하는데 큰 도움을 줍니다.

2. Optional 클래스

2.1 Optional 클래스가 뭐에요?

 Optional 클래스는 자바 8에서 도입된 클래스로, 값이 있을 수도 없을 수도 있는 상황을 다루기 위해 사용됩니다. 기존에는 값이 없을 때 null을 반환하거나 NullPointerException이 발생하는 경우가 많았지만, Optional 클래스를 사용하면 이러한 예외 상황을 깔끔하게 처리할 수 있습니다. Optional은 값을 감싸고 있는 래퍼 클래스로, 값이 존재할 경우 값을 제공하고, 값이 없을 경우에는 null 대신에 Optional.empty()를 반환합니다.

2.2 NullPointerException을 피하기

 Optional 클래스의 가장 큰 장점 중 하나는 NullPointerException을 피할 수 있다는 점입니다. Optional을 사용하면 값이 null인지 확인하고, 값이 존재하지 않는 경우에 대한 처리를 명시적으로 할 수 있습니다. 이를 통해 코드의 가독성과 안정성을 높일 수 있습니다.

다음은 Optional을 사용하지 않은 예제 코드입니다.

public class Main {
    public static void main(String[] args) {
        String name = getName();
        int length = name.length(); // NullPointerException 발생!
        System.out.println("이름 길이: " + length);
    }

    private static String getName() {
        return null;
    }
}

위의 예제에서는 getName() 메서드에서 null을 반환하고, 이를 name 변수에 할당한 후 length() 메서드를 호출합니다. 그 결과, NullPointerException이 발생하게 됩니다.

이번에는 Optional 클래스를 사용하여 NullPointerException을 피하는 방법을 살펴보겠습니다.

import java.util.Optional;

public class Main {
    public static void main(String[] args) {
        Optional<String> nameOptional = getName();
        if (nameOptional.isPresent()) {
            String name = nameOptional.get();
            int length = name.length();
            System.out.println("이름 길이: " + length);
        } else {
            System.out.println("이름이 없습니다.");
        }
    }

    private static Optional<String> getName() {
        return Optional.ofNullable(null);
    }
}

위의 코드에서는 getName() 메서드에서 Optional.ofNullable(null)을 사용하여 null을 감싼 Optional 객체를 반환합니다. 그리고 main() 메서드에서는 isPresent() 메서드를 사용하여 값의 존재 여부를 확인하고, 값이 존재하는 경우에는 get() 메서드를 사용하여 값을 가져옵니다. 값이 존재하지 않는 경우에는 else 블록에서 처리를 할 수 있습니다.

2.3 Optional의 다양한 활용법

Optional 클래스는 값이 없는 상황을 다루는 것뿐만 아니라 다양한 활용법을 제공합니다. 몇 가지 예시를 살펴보겠습니다.

2.3.1 orElse() 메서드

값이 존재하지 않을 때 기본 값을 제공할 수 있습니다.

Optional<String> nameOptional = getName();
String name = nameOptional.orElse("기본 이름");
System.out.println("이름: " + name);

2.3.2 ifPresent() 메서드

값이 존재할 경우에만 동작을 수행할 수 있습니다.

Optional<String> nameOptional = getName();
nameOptional.ifPresent(name -> System.out.println("이름: " + name));

2.3.3 map() 메서드.

값이 존재할 때 해당 값을 변환할 수 있습니다.

Optional<String> nameOptional = getName();
Optional<Integer> lengthOptional = nameOptional.map(String::length);

Optional 클래스는 이 외에도 많은 유용한 메서드를 제공하여 코드를 더욱 안전하고 가독성 있게 작성할 수 있도록 도와줍니다.

 

자바 8에서 소개된 인터페이스 디폴트 메서드와 Optional 클래스는 자바 개발을 더욱 친근하게 만들어주는 훌륭한 기능들입니다. 인터페이스 디폴트 메서드를 통해 기존 인터페이스를 유연하게 확장하고, Optional 클래스를 사용하여 예외 처리를 간단하게 다룰 수 있습니다. 이러한 기능들은 코드의 가독성과 유지 보수성을 향상시키며, 개발자들에게 더욱 큰 가능성과 자신감을 줍니다. 이제 함께 자세히 알아보도록 해요!

댓글

💲 추천 글