java 8 정리2

Java 정리 2021. 5. 13. 21:09

인프런 강의 5일차.

 - 더 자바, Java 8 (백기선 강사님)

 

1. 메소드 레퍼런스

 - 람다가 하는 일이 기존 메소드 또는 생성자를 호출하는 거라면, 메소드 레퍼런스를 사용해서 매우 간결하게 표현가능

 - 메소드 레퍼런스 참조 방법

스태틱 메소드 참조 타입::스태틱 메소드
특정 객체의 인스턴스 메소드 참조 객체 레퍼런스::인스턴스 메소드
임의 객체의 인스턴스 메소드 참조 타입::인스턴스 메소드
생성자 참조 타입::new

    -> 메소드 또는 생성자의 매개변수로 람다의 입력값을 받는다

    -> 리턴값 또는 생성한 객체는 람다의 리턴값이다.

package me.whiteship.java8to11;

import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

public class App {

    public static void main(String[] args) {
        UnaryOperator<String> hi = (s) -> "hi " + s;
        UnaryOperator<String> staticMethodHi = Greeting::hi;        //hi와 staticMethodHi는 동일한 결과를 같는다.

        Supplier<Greeting> newGreeting = Greeting::new;     //Supplier는 선언하더라도 아무런 일이 발생하지 않는다.
        //newGreeting.get() 해야 뭐라도 만들어짐.

        Greeting greeting = new Greeting();
        UnaryOperator<String> hello = greeting::hello;
        System.out.println(hello.apply("Park"));

        Function<String, Greeting> parkGreeting = Greeting::new;        //Supplier와 똑같은 Greeting::new 이지만 다른 생성자를 참조한다.
        Greeting park = parkGreeting.apply("park");
        System.out.println(park.getName());

        String[] names = {"park", "whiteship", "toby"};

        //case1. names를 정렬시킬 때 특정한 조건(compare에 구현된 조건)으로 정렬
        /*Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return 0;
            }
        }*/
        //case2. new Comparator를 람다로 치환
        Arrays.sort(names, (o1, o2) -> 0);

        //case3. case2를 메소드 레퍼런스로 가져다 사용
        Arrays.sort(names, String::compareToIgnoreCase);

        System.out.println(Arrays.toString(names));

    }

}

 

2. 인터페이스 기본 메소드와 스태틱 메소드

 - 기본 메소드(Default Method)

    -> 메소드 또는 생성자의 매개변수로 람다의 입력값을 받는다   

    -> 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.

        * 컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다.

        * 반드시 문서화 할 것. (@ImplSpec 자바독 태그 사용)

    -> Object class가 제공하는 기능 (equals, hasCode)는 기본 메소드로 제공할 수 없다.

        * 구현체가 재정의해야 한다.

    -> 본인이 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.

    -> 인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경할 수 있다.

    -> 인터페이스 구현체가 재정의 할 수도 있다.

 

 - 스태틱 메소드

    -> 해당 타입 관련 헬터 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.

 

package me.whiteship.java8to11;

import java.util.Arrays;
import java.util.Comparator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;

public class App {

    public static void main(String[] args) {
        GreetingInterface greetingInterface = new DefaultGreeting("park");
        greetingInterface.printName();              //park 출력
        greetingInterface.printNameUpperCase();     //PARK 출력

        GreetingInterface.printAnything();      //Interface의 static 메소드 바로 사용
    }

}


package me.whiteship.java8to11;

public interface GreetingInterface {

    void printName();

    //case1. 만약 printName()만 존재하는 인터페이스에 새로 추상 메소드를 추가할 경우 해당 인터페이스를 구현한 모든 클래스는 컴파일 에러가 발생한다(추가된 메소드를 구현하지 않았기 때문!)
    //void printNameUpperCase();

    //case2. 헌데 모든 클래스에 새로 추가되는 추상 메소드를 구현하지 않아도 컴파일 에러를 발생시키지 않는 방법은 Default 메소드로 선언하는 것이다.
    /*default void printNameUpperCase(){
        System.out.println("default Greeting");
    }*/

    /**
     * @implSpec
     * 이 구현체는 getName()으로 가져온 문자열을 대문자로 바꿔 출력한다.
     * 기본 메소드는 구현체가 모르게 추가된 기능이기 때문에 null로 온 경우 런타임 익셉션이 발생할 수 있다.(문서화 필수!)
     */
    //case3. 아래와 같은 형태로도 사용이 가능하다.
    default void printNameUpperCase(){
        System.out.println(getName().toUpperCase());
    }

    //static 메소드
    static void printAnything(){
        System.out.println("GreetingInterface");
    }

    String getName();
}


package me.whiteship.java8to11;

public interface Bar {
    //GreetingInterface가 제공하는 기본 구현체를 제공하고 싶지 않을 경우 Bar에서 해당 구현체를 다시 추상 메소드로 구현하면 된다 extends GreetingInterface
    //void printNameUpperCase() ;
    //아무것도 선언하지 않을 시 기본 오버라이딩
    //만약 Bar와 GreetingInterface에 같은 이름의 기본 구현체가 있고, 이를 implements하는 경우 에러가 발생한다.
    default void printNameUpperCase(){
        System.out.println("BAR");
    }
}


package me.whiteship.java8to11;

public class DefaultGreeting implements GreetingInterface, Bar{
    //Bar를 추가한 경우 두 인터페이스에 같이 구현된 기본 구현체인 printNameUpperCase 충돌이 발생한다.
    //충돌이 발생하는 경우 DefaultGreeting에서 직접 기본 구현체를 오버라이딩해서 구현해야 한다.

    String name;

    public DefaultGreeting(String name) {
        this.name = name;
    }

    @Override
    public void printName() {
        System.out.println(this.name);
    }

    //GreetingInterface, Bar에 printNameUpperCase라는 기본 구현체가 있으므로 오버라이딩 해야 컴파일 오류가 발생하지 않음
    @Override
    public void printNameUpperCase() {

    }

    @Override
    public String getName() {
        return this.name;
    }
}

'Java 정리' 카테고리의 다른 글

java 8 정리6  (0) 2021.05.21
java 8 정리5  (0) 2021.05.20
java 8 정리4  (0) 2021.05.19
java 8 정리3  (0) 2021.05.17
java 8 정리1  (0) 2021.05.12