1장. 프로그래밍이란 무엇인가?

공부하는 감자·2023년 11월 26일
0

자바의 신 3판

목록 보기
1/30

들어가기 전

『자바의 신 3판』 을 읽고 내용 정리 및 공부한 내용을 정리한 글입니다.
서적: 자바의 신 3판 구입처

내용 정리

프로그래밍이란

프로그래밍은 컴퓨터에게 할 일을 가르치는 것이다. 프로그래밍을 한다는 건 작은 프로그램들을 반복적으로 수행하면서 어떤 기능들을 만들어내는 것이다.

프로그램을 만들려면 언어가 필요하다. 사람과 사람 사이에 의사소통을 위해서는 언어가 필요하듯이, 사람과 컴퓨터 사이에도 언어가 필요하다. 이러한 언어를 프로그래밍 언어라고 한다.

객체지향 언어

자바와 같은 언어를 객체지향 프로그래밍 언어(Object Oriented Programming Language)라고 한다.

지금까지 대부분의 프로그래밍 언어들은 현실과 동떨어져 있었다. 하지만 객체지향 언어의 등장으로 현실 세계를 프로그램으로 표현할 수 있게 된다. 사물과 추상적인 것도 클래스가 될 수 있다.

클래스와 메소드

💡 자바의 가장 작은 단위는 클래스이다.

자바에서는 어떤 값을 주고 결과를 넘겨받는 것을 메소드(method)라고 한다. 메소드는 다음과 같이 구성되어 있다.

{접근제어자} {리턴 타입} {메소드명} (매개변수,)
ex)
public int sum(num1, num2) {}

메소드는 클래스에 소속되어 있어야만 한다. 클래스는 다음과 같이 사용한다.

{접근제어자} class {클래스명} {}
ex)
public class calculater {}

클래스는 다음의 조건을 만족해야 한다.

클래스는 상태(state)와 행동(behavior)을 가지고 있어야만 한다.

여기서 상태는 변수를, 행동은 메소드를 의미한다.

상태는 클래스의 특성을 결정짓는 것을 말하며, 클래스 안에, 메소드 밖에 정의한다.

객체지향을 이야기할 때 “클래스는 상태와 행동이 있어야만 한다”고 보통 이야기하지만, 반드시 상태와 행동이 있어야만 하는 것은 아니다.

세미콜론

모든 자바 코드의 한 줄이 끝날 때에는 세미콜론(;)을 적어주어야 한다. 그렇지 않으면 그 다음 줄도 같은 줄로 생각한다.

자바에서는 인덴트(indent)를 별로 신경 쓰지 않는다. 인덴트라는 것은 코드 앞의 공백을 말하는데, 주로 탭(tab)을 눌러 이러한 공백을 만든다.

일부 다른 프로그래밍 언어(Python 등)의 경우 인덴트를 매우 중요하게 여기기도 하는데, 자바는 그렇지 않다.

그렇다고 인덴트를 무시하고 작성할 경우 코드의 가독성이 떨어지니, 중괄호가 한 번 시작하면 탭을 한 번씩 더 입력하자.

예약어(reserved word)

모든 프로그래밍 언어에는 예약어라는 것이 있다. 예약어라는 것은 “예약되어 있으니까 쓰지 못하는 언어”라고 보면 된다.

예약어는 클래스, 메소드, 변수의 이름으로 사용할 수 없다.

정리해 봅시다.

질문에 대한 제 정답을 적은 것이며, 구글폼 제출 후 답은 직접 확인하시는 것을 추천 드립니다.
자바의 신 3판 문제 풀기 사이트

Q. 클래스가 뭔가요?

Me: 클래스는 자바의 가장 작은 단위입니다.

Q. 메소드가 뭔가요?

Me: 메소드는 클래스의 행위로, 호출하면 실행됩니다. 입력 값을 넣으면 결과를 돌려주는데, 입력 값 없이 호출할 수도 있습니다.

Q. 메소드의 매개 변수는 어디에 적어주나요?

Me: 메소드의 매개 변수는 메소드 명 우측에 소괄호 안에 적어줍니다. 매개 변수는 없을 수도 있고, 무수히 많을 수도 있습니다.

Q. 메소드 이름 앞에 꼭 적어 줘야 하는 건 뭐죠?

Me: 메소드 이름 앞에는 접근 제어자와 리턴 타입이 있어야 합니다.

Q. 클래스가 갖고 있어야 한다고 한 두 가지가 뭐죠?

Me: 클래스는 상태(state)와 행동(behavior)을 가지고 있어야만 합니다. 상태는 클래스 안에, 메소드 밖에 위치해야 하며 변수를 말합니다. 행동은 메소드에 해당합니다.

Q. 메소드에서 결과를 돌려주려면 어떤 예약어를 사용해야 하나요?

Me: 메소드 내부에서 return 이라는 예약어를 사용해 결과를 반환합니다.

질문

💡 책에 있는 내용이 아닙니다.

책을 읽으며 설명이 더 필요하거나, 추가로 궁금한 점에 대해 질문 형식으로 작성 후, 답을 구해보고 있습니다.
참고한 사이트나 영상은 [출처]로 달아두었으며, 오류 지적은 언제나 환영합니다.

Q. 컴파일될 때 주석은 어떻게 되는가?

테스트 툴: VSCode

테스트 코드 (16장의 예제)

public interface KeyEventListener {
    // 한글 주석
    public void onKeyDown();
    public void onKeyUp();
}
public class InputBox {
    public InputBox() {

    }

    KeyEventListener listener;
    public void setKeyListener(KeyEventListener listener) {
        this.listener = listener;
    }

    public static final int KEY_DOWN = 2;
    public static final int KEY_UP = 4;
    public void listenerCalled(int eventType) {
        if (eventType == KEY_DOWN) {
            listener.onKeyDown();
        } else if (eventType == KEY_UP) {
            listener.onKeyUp();
        }
    }
}
public class MyPage {
    public InputBox input ;

    public void setUI() {
        input = new InputBox();
        // input.setKeyListener(new KeyEventListener() {
        //     public void onKeyDown() {
        //         System.out.println("Key Down");
        //     }
        //     public void onKeyUp() {
        //         System.out.println("Key Up");
        //     }
        // });
        KeyEventListener listener = new KeyEventListener() {
            public void onKeyDown() {
                System.out.println("Key Down");
            }
            public void onKeyUp() {
                System.out.println("Key Up");
            }
        };
        input.setKeyListener(listener);
    }

    public void pressKey() {
        input.listenerCalled(InputBox.KEY_DOWN);
        input.listenerCalled(InputBox.KEY_UP);
    }

    public static void main(String[] args) {
        MyPage maPage = new MyPage();
        maPage.setUI();
        maPage.pressKey();
    }
}

컴파일 시 주석을 읽는다.

인코딩의 문제가 있었는데, 덕분에 컴파일 시 주석에 한글로 적으면 한글을 인식하지 못해 컴파일러가 오류를 뱉어내는 것을 확인할 수 있었다.

즉, 컴파일러는 컴파일할 때 주석을 읽기는 한다. (당연한 말이지만)

디컴파일 시

💡 디컴파일이란?
컴파일하여 나온 클래스 파일을, 역으로 자바 파일로 변환하여 보는 것. 이 과정에서 원본의 코드가 그대로 나오는 것은 아니다.

테스트 코드를 컴파일하면, 총 4개의 클래스 파일이 생긴다. 각각의 클래스를 컴파일하여 나온 클래스 파일로 나온 것과 MyPage.java에 있던 익명 클래스(내부 클래스)가 MyPage$.class로 나온 것을 볼 수 있다.

여기에서, MyPage.java에는 다음과 같이 주석이 있었다.

VSCode에서는 .class 파일을 클릭하여 디컴파일할 수 있다.

위 사진이 바로 MyPage.class 파일이다. 이 파일을 보면, 주석문은 깔끔하게 사라진 것을 확인할 수 있다.

결론

컴파일 시에는 주석문을 읽지만, 빌드 시에는 주석문이 사라지므로 영향을 미치지 않는다.

Q. 컴파일될 때 안쓰는 import 선언문은 없어진다는데, 코드 상에서 없애줘야할 필요가 있을까?

import * 를 사용하거나, 사용하지 않는 import 문을 지우지 않은 경우 컴파일 시에는 영향이 조금 있을 수도 있다.

하지만, 컴파일을 하면서 사용하지 않는 import는 자동으로 삭제해주기 때문에 빌드 후 실행한 후에는 영향이 없다.

추가로 보면 좋을 참고 사이트
JDK 예전 버전에서는 *를 쓸 경우 모든 Class를 Method Area에 등록 시켜 놓아서 약간의 메모리 낭비와 성능 낭비가 있었다.
하지만 지금은 동적으로 Class Loading을 하기 때문에 현재는 차이가 없다.

그렇다면 왜, 사용하지 않는 import를 삭제해 주어야 하는가?

실행 시에는 문제가 없다지만, 가독성을 위해서 삭제해주는 편이 좋다. 가독성은 협업 시 아주 중요한 문제라고 생각한다.
사용하는 클래스만 선언해주는 것이, 어떤 기능에 필요해서 가져온 것인지 알 수 있다. 사용하지도 않을 것들을 본인 편의에 의해 *로 한 번에 가져오는 것보다는, 꼭 필요한 것만 가져오는 게 좋지 않을까?

Q. 클래스의 상태는 무엇인가?

클래스란 객체를 만들어내기 위한 설계도라고 다들 이야기한다. 먼저 우리는 객체와 클래스의 차이에 대해 알 필요가 있다.

객체지향은 실세계에 있는 사물이나 개념을 추상화하여 코드로 옮긴 것이다. 이때, 실세계의 것을 객체라고 하고 추상화한 것을 클래스라고 한다.

예를 들어, 흔히 예를 드는 자동차를 보자. 자동차를 객체로 생각하고 추상화한다면 자동차가 같은 속성은 다음과 같이 있을 수 있다.
1. 기종 (이름)
2. 색상
3. 크기

그리고 자동차가 할 수 있는 동작은 다음과 같이 있을 수 있다.
1. 시동 걸기
2. 엑셀 밟기 (전진)
3. 브레이크

이 때, 객체의 속성이 클래스의 상태, 동작이 클래스의 행위가 된다고 생각할 수 있겠다.

다시 말해서, 우리가 추상화해 놓은 객체의 속성들이 클래스의 상태이다.

Q. 클래스의 상태는 변한다?

단순하게 생각하자. 클래스의 상태는 변수라고들 말한다. 그렇다면, 그 변수의 값이 변할 수 있는가?

코딩을 해본 사람이라면 알겠지만, 상수가 아니라면 당연히 변수의 값은 변할 수 있다. 애당초 '변수'의 뜻 자체가 '변하는 숫자'라는 의미다.

실세계의 관점으로도 생각해보자. 우리는 보통 상태를 행위를 통해서 변경한다.

몇 가지 예를 들어 보자.
1. 살이 쪘다면(상태), 우리는 운동(행위)을 해서 살을 뺀다(변경).
2. 핸드폰의 전원이 꺼져있다면(상태), 전원 버튼을 눌러(행위) 핸드폰을 켠다(변경) .

마찬가지로 클래스의 변수(상태)는 초기값이 있을 것이다. 그리고, 메소드(행위)를 호출할 때마다 변수의 값이 변할 수 있다.

정리하자면, 행위를 통해 상태는 변경된다.

Q. 상태는 버그를 유발하는가?

"변수가 존재하고, 이 변수를 통해 객체가 예측할 수 없는 상태를 갖게 되어 애플리케이션 내부에서 버그를 발생시킨다"

클래스의 상태에 관련하여 찾다가 위 문구를 발견했다.

객체지향으로 설계를 했다는 건, 객체의 상태를 직접적으로 접근 및 변경할 수 없도록 하고 행위를 통해서 상태에 영향을 주어야 하는 거라고 이해했다. (캡슐화)

그러니 "변수를 통해 객체가 예측할 수 없는 상태를 갖는다" 라는 게 잘 이해가 가지 않았다.

관련하여 찾아보아도, 이에 대한 자세한 설명을 한 곳이 없었다. 물론, 내가 못 찾은 것일 수도 있고 나 홀로 이해력이 좋지 않은 것일 수도 있다….

아무튼, 관련해서 F-Lab 멘토님께 어떤 방향으로 보면 좋을 지 조언을 구했다.

멘토님 답변: 찾아보신 내용에서 변수를 통해란 의미는 외부에 노출된 변경이 용이한 데이터를 의미하는 것 같네요. 말씀해주신 변수란 단어는 좀 광범위해서 클래스 내의 ”속성“으로 “행위”를 통해서 변경하는 것으로 바라보면 어떨까 싶어요.

결론

먼저, 사이드 이펙트라는 말을 알아야 한다. 부수효과라는 뜻으로, 위키피디아에서는 다음과 같이 정의한다.

In computer science, an operation, function or expression is said to have a side effect if it modifies some state variable value(s) outside its local environment, which is to say if it has any observable effect other than its primary effect of returning a value to the invoker of the operation.

그리고 하단 사이트에 기재한 곳에서는 다음과 같이 정의했다.

A side effect is an interaction with the outside world.

사이드 이펙트에는 아래와 같은 것들이 포함된다고 한다.

  • 지역변수가 아닌 변수를 변경
  • static 지역 변수를 변경
  • passed by reference로 넘어온 매개변수 변경
  • I/O 수행
    • 파일을 읽거나 쓰는 것
  • 콘솔에 로그를 출력
  • side-effects가 있는 다른 함수 실행

하단의 참고 사이트를 보면 알겠지만, 사이드 이펙트를 어떻게 정의하느냐에 대해 사람들이 글을 많이 써두었다.

수학적 관점에서 보는 사람도 있고, 약을 많이 복용했을 때의 상황을 예로 드는 사람도 있다.

간단하게 정리하면, 함수가 연산의 호출자에게 값을 반환하는 일차적인 효과(함수의 목적) 외의 외부와 상호작용하는 어떠한 효과를 사이드 이펙트라고 말하는 것 같다.

내가 원하는 '상태'를 변경하는 사이드 이펙트는 다음과 같은 예를 들어볼 수 있겠다.
1. 메소드 내에서 클래스 변수나 인스턴스 변수를 사용하는데, 이 두 변수가 변경되면 메소드의 출력 값이 변경된다.
2. 객체를 매개 변수로 받아 값을 증가해주는 메소드와 감소해주는 메소드가 있을 때, 이 메소드들의 순서에 따라 출력 결과가 바뀐다.

더 다양한 케이스가 있을 수 있지만, 나는 이런 식으로 예를 들어봤다.

정리하자면 객체지향에서는 상태는 변하는 값이기 때문에, 외부 동작에 따라 값이 변경되어 예상치 못한 오류를 발생시킬 위험이 있을 수 있다는 말인 것 같다.

여담으로 사이드 이펙트는 프로그램의 동작을 이해하고 예측하기 어렵게 만들어서, 상태를 멀리하고 사이드 이펙트를 최소한으로 줄이는 함수형 프로그래밍이 주목받는다고 한다.

참고 사이트

DEV Community - Side effects
What is a "side effect?"

profile
책을 읽거나 강의를 들으며 공부한 내용을 정리합니다. 가끔 개발하는데 있었던 이슈도 올립니다.

0개의 댓글