Justin의 개발 로그
article thumbnail

전통적으로 프로그래밍 언어에는 언어의 구성원(참조, 객체, 클래스, 메소드 등)에게 일급 시민과 이급 시민이라는 등급이 존재한다.

 

Java 7 까지 분류

Java 8~ 이후 메소드도 1급 시민권을 획득

 

함수형 프로그래밍이 떠오르면서 1급 객체(First-class citizen)란 말을 많이 듣게 되는 것 같다. 1급 객체의 특징은 아래와 같다. 아래 1급시민의 3가지 조건을 충족하는 객체라면 1급객체 라고 할수 있다.

1급 시민의 조건 3가지
1. 변수나 데이타에 할당 할 수 있어야 한다.
2. 객체의 인자로 넘길 수 있어야 한다.
3. 객체의 리턴값으로 리턴 할수 있어야 한다.

주로 사용하고 있는 언어인 JAVA에서는, 함수가 1급 객체에 해당하지 않는다. Kotlin, JavaScript 등의 언어에서는 변수에 함수를 할당하고 사용할 수 있다. JAVA는 원래 불가능하지만 JAVA 8 부터는 위 언어들과 같은 1급 객체로의 취급이 가능해진다.

예를 들어 JS는 변수에 함수를 할당 가능

var variable = function func(){
	console.log('hi');
}


그러나 자바는 불가능

BUT 익명 클래스 사용 하여 마치 함수를 넘기는 듯한 역할을 부여할 수 있음

Test test = new Test(){
	System.out.println("hi");
};

또한 Lambda도 마찬가지로 내부적으로 익명 클래스와 같게 처리되므로 Lambda와 익명클래스는 같다고 할 수 있다.

이는 메서드가 1개만 존재하는 인터페이스/클래스를 통해, 마치 함수를 전달하는 것처럼 여겨서, 함수를 1급 객체로 취급하지 않는 JAVA의 단점을 어느정도나마 해결한 것이라고 볼 수 있다.

 

유의할 점

Lambda와 익명클래스의 처리방식이 내부적으로 익명을 유지한다는 것이 유사할 뿐 둘이 같은 개념이라고 볼 수 없다.

그렇다면 여기서 파생되는 질문이 하나 있다. 둘의 차이점은 무엇인가?

 

익명 클래스 VS Lambda

  1. 익명 클래스는 익명의 새로운 클래스를 생성하지만 Lambda는 새로운 메서드를 생성
  2. 익명 클래스의 this는 새로 생성된 클래스 / Lambda의 this는 Lambda를 가진 클래스

 

왜 자바는 메소드를 1급 시민으로 만들었나?

 

"함수 - 1급 시민, 1급 객체(First Class Citizen, First Class Object)"

파이썬에서 함수는 1급 시민입니다. 1급 시민이라니.. 뭔가 특별한 대우를 받을것만 갖죠? 네 맞습니다. 파이썬에서는 함수가 매우 특별합니다. 그리고 함수가 1급 시민 이기 때문에 파이썬에서는 함수형 프로그래밍이 가능합니다.

 

위키피디아에서 1급시민에 대해 검색하면 다음과 같은 설명이 나옵니다.

1. All items can be the actual parameters of functions
2. All items can be returned as results of functions
3. All items can be the subject of assignment statements
4. All items can be tested for equality.

 

위 내용을 요약한뒤 번역해 보면 다음과 같습니다.

  • 함수는 다른 함수의 인자(매개변수)로 전달될 수 있다. (callback 함수)
  • 함수는 다른 함수의 결과로서 반환될 수 있다. (수학에서의 합성함수 표현)
  • 함수는 변수에 할당될 수 있다. (Binding)

 

함수는 다른함수의 인자(파라미터)로 전달될 수 있다. - callback 함수

콜백 함수는 다른 함수의 인자로 전달되는 함수입니다. 콜백함수를 전달받은 함수는 콜백함수를 호출(invoke:부르다)한다. GUI프로그래밍이나 비동기 프로그래밍에 사용됩니다. 

#에러메세지 출력 함수
def error_msg():
    return("you have limited access")

#단어의 첫글자만 대문자로 만드는 함수
def Char(msg):
    T = msg.title()
    return T


if __name__ == '__main__':
    result = Char(error_msg())
    print(result)

 

 

함수는 다른 함수의 결과로서 반환될 수 있다. - 수학에서 합성함수 표현

말 그대로 return값으로 함수를 쓸 수 있습니다. 수학에서 합성함수를 표현할 때 사용될 수 있습니다. 

def func1(x):
    return 2*x

def func2(x):
    y = x+3
    return func1(y)

 

 

함수는 변수에 할당될 수 있다. - binding

error_msg()함수를 a라는 변수에 할당 했습니다. 변수에 할당할때는 소괄호를 빼고 함수 이름만 씁니다. 소괄호를 붙이는 것은 호출(call)이죠. 이렇게 변수에 할당하는 것을  binding이라고 부르기도 합니다. 

변수 b에는 내장함수 sorted() binding하였습니다.  

def error_msg():
    return("you have limited access")


if __name__ == '__main__':
    a = error_msg
    b = sorted
    print(a)
    print(b)

출력 결과

 

파이썬 에서 "모든것이 객체다" 라는 말 들어 보셨죠? 그 중에서도 으뜸은 함수입니다. 그리고 함수형 프로그래밍은 모든 것을 객체로 표현하게끔 하는 것입니다.

 

다른 프로그래밍 언어는 어떨까요?

  • 함수가 일급 시민인 언어 : Javascript, Scala, Go 등
  • 함수가 일급 시민이 아닌 언어 : C, Java 등

 

Java 함수형 프로그래밍으로 달라진 점

기존 함수 참조 전달 방식

  • new Interface명()으로 익명 클래스를 만들어 익명 클래스의 인스턴스를 전달하는 방식으로 
    함수형 프로그래밍인 것처럼 구현을 할 수 있다.
  • 이렇게 만든 익명 클래스는 재활용이 불가능하다.
  • 익명이 아닌 클래스를 만들어서 클래스의 인스턴스(new Class())를 전달할 수 있지만, 
    그렇게 하면 클래스의 인스턴스(참조값)을 넘기는 방식이며, 함수형 프로그래밍이 아니다.
import org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;

public class LambdaTest {

    @Test
    void oldFashionTest() {
        File[] hiddenFiles = new File(".").listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.isHidden();
            }
        });

        Arrays.stream(hiddenFiles).forEach(System.out::println);
    }
}

익명 클래스 인스턴스 동작 방식

 

 

Java8 함수 참조 방식

  • :: 자바 8의 메서드 참조(method reference, '이 메서드를 값으로 사용하라'는 의미)
  • 메서드 참조를 이용해서 메서드를 직접 인자로 전달할 수 있다.
mport org.junit.jupiter.api.Test;

import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;

public class LambdaTest {

    @Test
    void java8StyleTest() {
        File[] hiddenFiles = new File(".").listFiles(File::isHidden);

        Arrays.stream(hiddenFiles).forEach(System.out::println);
    }
}

 

profile

Justin의 개발 로그

@라이프노트

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!