NaKaLiGoBa/Book-Study

일급 객체와 이급 객체에 대해

Opened this issue · 2 comments

각각의 의미를 명확히 알아두려고 하는데 일단 이슈로 등록하겠습니다

책에도 나오다시피 함수형 프로그래밍에서 1급 객체라는 말이 많이 언급된다고 합니다.

제가 조사한 1급 객체란, 3가지 조건을 충족해야 된다고 합니다.
1. 변수나 데이터에 할당할 수 있어야 한다.
2. 객체의 인자로 넘길 수 있어야 한다.
3. 객체의 리턴값으로 리턴할 수 있어야 한다.

Java 8 이전에는 1급 객체로서의 함수를 다룰 수 없었는데, Java 8 부터 람다 표현식함수형 인터페이스의 도입으로
1급 객체로서의 함수를 다룰 수 있게 되었습니다.

object Main {
    @JvmStatic
    fun main(args: Array<String>) {
        val a = test
    }

    val test: () -> Unit = { println("kotlin") }
}

위의 Kotlin의 예시로는 람다 표현식을 이용하고 있는데, 이렇게 함수를 변수에 할당하거나
다른 변수에 전달하는 것을 1급 객체의 특성 중 하나를 보여주는 코드입니다.

public class java {

    public static void test(){
        System.out.println("java");
    }

    public static void main(String[] args) {
        System.out.println("java");
//        Object a = test;
    }
}

위의 자바 코드는 함수를 직접적으로 변수에 할당하지 않아 직접적으로 변수에 할당되거나
다른 함수에 전달되는 것이 아니므로 1급 객체의 조건을 지키지 못하고 있습니다.
Java 8 이후에서는 람다 표현식과 함수형 인터페이스를 사용하여 함수를 변수에 할당하거나
다른 함수에 전달할 수 있게 되었습니다.

위의 자바 코드에서 test() 메서드를 람다 표현식으로 표현하려면 함수형 인터페이스가 필요한데,
Java에서는 이러한 역할을 하는 Runnable,Thread, '람다', '익명 클래스'를 활용할 수 있다고 합니다.

public class JavaExample {

    public static void main(String[] args) {
        // 1. 변수에 할당
        Runnable test = () -> System.out.println("java");
        test.run();

        // 2. 함수의 인자로 전달
        processRunnable(() -> System.out.println("Passed as an argument"));

        // 3. 함수의 반환값으로 사용
        Runnable returnedRunnable = getRunnable();
        returnedRunnable.run();
    }

    private static void processRunnable(Runnable runnable) {
        runnable.run();
    }

    private static Runnable getRunnable() {
        return () -> System.out.println("Returned as a result");
    }
}

위의 코드는 'Runnable'을 사용하여 'test'메서드를 람다 표현식으로 표현한 예시입니다.

Java에서 람다 표현식은 익명 함수를 나타내기 위한 축약형 문법으로, 자바에서는
람다 표현식을 함수형 인터페이스를 구현하는 익명 클래스의 인스턴스로 간주합니다.
따라서, 람다 표현식만으로는 단독으로 1급 객체를 만들 수 없어,
함수형 인터페이스의 인스턴스를 생성하게 되고, 이 인스턴스를 변수에 할당하거나 인자로 전달하는 등의
동작을 통해 1급 객체의 특성을 활용할 수 있다고 합니다.

// 람다 표현식을 사용하여 함수형 인터페이스를 구현하고 변수에 할당하는 예시.
interface MyFunctionalInterface {
    void myMethod();
}

public class JavaExample {

    public static void main(String[] args) {
        // 람다 표현식을 사용하여 MyFunctionalInterface를 구현한 인스턴스를 생성
        MyFunctionalInterface myFunctionalInterface = () -> System.out.println("Lambda - java");
        
        // 생성한 인스턴스를 변수에 할당
        myFunctionalInterface.myMethod();
        
        // 다른 변수에도 할당 가능
        MyFunctionalInterface anotherFunctionalInterface = myFunctionalInterface;
        anotherFunctionalInterface.myMethod();
    }
}

Runnable 인터페이스는 단일 추상 메서드(run() 메서드)를 갖는 함수형 인터페이스이기 때문에 람다표현식과
잘 어울린다고 합니다.

또한, 자바에서는 다중 상속이 지원되지 않아, Thread 클래스를 상속받으면 다른 클래스를 상속받을 수 있어
좋지 않아 대부분 Runnable 인터페이스를 사용한다고 합니다.

복붙이 아닌 여러 블로그의 글들을 조합하면서 작성하다보니 두서 없이 작성했는데,
혹시 추가적인 내용이나 틀린 내용이 있다면 말씀해주세요!

https://medium.com/@lazysoul/functional-programming-%EC%97%90%EC%84%9C-1%EA%B8%89-%EA%B0%9D%EC%B2%B4%EB%9E%80-ba1aeb048059

https://mangkyu.tistory.com/258