ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JAVA8에 대해 알아보자(1)
    카테고리 없음 2023. 4. 18. 12:31

    java8

    자바8의 새롭게 바뀐 부분이 많지만 그 중 내가 자주 쓰는걸 정리 해보겠다.

    @FunctionalInterface

    첫 번째로 @FunctionalInterface 인터페이스다. 람다를 쓰긴 위한 애노테이션이다. 만약 저 애노테이션이 붙은거라면 람다 표현식을 사용 할 수 있다. 하지만 명시적으로 지정 하지 않더라도 abstract 메소드가 한개라면 람바 표현식을 사용 할 수 있다. 만약 저 애노테이션을 사용한다면 abstract 메소드가 2개 이상 있을경우 컴파일 타임에 에러가 난다. 자바 기본 패키지에 있는 Function이라는 인터페이스다.
    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T t);
    
        //...
    }
    
    한번 커스텀한 interface를 만들어보자. 두개의 같은 타입 파라미터를 넘겨서 두개를 더하는 인터페이스다.
    @FunctionalInterface
    interface AddFunction<T> {
    
        T apply(T t, T t1);
    }
    
    사용해 보자
    AddFunction<Integer> add = (i, j) -> i + j;
    System.out.println(add.apply(10, 20));
    
    AddFunction<String> add1 = (i, j) -> i + j;
    System.out.println(add1.apply("hello", " world"));
    
    결과는 다음과 같을 것이다.
    30
    hello world
    

    lambda

    두 번째론 람다표현식이다. 자바 개발자 한테는 조금 생소한 표현식 이다. 하지만 다른 언어들은 일찌감치 람다 표현식을 사용하고 있다. 스칼라, 파이썬 하스켈, c#등 여러가지 언어에서 사용 하고 있다. 한번 살펴보자. 우리가 쓰레드를 사용 할때 이용하는 인터페이스중 Runnable가 있다. 이 것도 java8에선 FunctionalInterface로 구현되었다.
    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }
    
    우리가 java8 이전에는 이렇게 사용하곤 했다. 우리가 흔히 말하는 익명 클래스다. 예를 든 코드다 실질적으로 이렇게 사용하진 않는다.
    Runnable runnable = new Runnable() {
         @Override
         public void run() {
             System.out.println("run 호출");
         }
    };
    runnable.run();
    
    그런데 람바를 쓰면 아주 간단하게 바뀐다. 한번보자.
    Runnable runnable = () -> System.out.println("run 호출");
    runnable.run();
    
    6줄을 단 한줄로 바꿔버렸다. 대단하다. 그럼 어떻게 바뀌는지 한번 보자. () 이거는 파라미터다 Runnableabstract 메소드 run은 받는 파라미터가 한개도 없다. 그래서 괄호만 해주는거다. -> 애로우?라 부른다? 람다? 인가? 흠 그리고 다음 나오는게 메소드 바디이다. 간단하다. 그럼 다음 예제도 살펴보자 이번엔 아까 위에서 봤던 Function 인터페이스다. 이 인터페이스를 아마 자주 사용할 듯 하다. 일단 람다를 쓰지말고 한번 해보자.
    Function<Integer,String> function = new Function<Integer, String>() {
        @Override
        public String apply(Integer integer) {
            return String.valueOf(integer);
        }
    };
    String str = function.apply(1010);
    System.out.println(str);
    
    일단 Function 인터페이스는 제네릭타입이다. 첫 번째는 파라미터타입 두 번째는 리턴 타입이다. 한마디로 어떤 타입의 파라미터로 넘기면 다른 타입을 반환하는걸 의미한다. 같은 타입을 지정해도 상관없다. 이런걸 identity라 부른다. 위의 코드는 int를 String으로 변환하는 코드다. 이제 람다로 바꿔보자!
    Function<Integer,String> function = x -> String.valueOf(x);
    String str = function.apply(1010);
    System.out.println(str);
    
    이것도 아주 깔끔하고 짧게 바뀌었다. 다시 한번 살펴보자. apply 메소드는 파라미터가 한개다.그래서 x라는 변수 한개를 선언했다.(파라미터가 한개일땐 ()로 감싸주지 않아도 된다.) 그리고 그 x로 String.valuOf를 이용하여 변환 하였다. 그런데 String.valueOf를 호출하기전에 그 파라미터가 어떤건지 한번 Print로 출력하고 싶다. 그럼 메소드 바디를 감싸주면 된다. 컬리브레이스로 감싸자 해보자.
    Function<Integer,String> function = x -> {
        System.out.println(x);
        return String.valueOf(x);
    };
    
    이외에도 자주 쓰는 인터페이스는 Consumer<T> 어떤 타입의 파라미터로 받는다 리턴은 없다. Predicate<T> 어떤 타입의 파라미터로 받는다 리턴은 Boolean 이다. Supplier<T> 어떤 타입으로 리턴한다. 파라미터는 없다. 이 외에도 java.util.function 패키지에 가보면 function 인터페이스가 있다. 한번씩 보자! 다음 시간에 Stream을 공부해보겠다.

    댓글

Designed by Tistory.