본문으로 건너뛰기

안동민 개발노트

본문 시작

처음 만나는 Java 오류

컴파일 오류, 클래스 탐색 오류, 실행 중 오류를 각각 재현하고 메시지에서 고칠 위치를 찾습니다.

오류 메시지는 실패 그 자체가 아니라 어느 단계까지 성공했는지 알려 주는 기록입니다.

먼저 컴파일 중인지, 클래스를 찾는 중인지, main을 실행한 뒤인지를 구분하면 고칠 위치가 좁아집니다.

HTML 다이어그램: /docs/java/ch1/ch1-4/1.html

컴파일 오류: 문법을 읽을 수 없음

src/BrokenSyntax.java를 다음처럼 저장합니다.

출력문 끝의 세미콜론을 일부러 빠뜨렸습니다.

src/BrokenSyntax.java — 일부러 실패하는 파일
public class BrokenSyntax {
    public static void main(String[] args) {
        System.out.println("semicolon missing")
    }
}
javac -d out src/BrokenSyntax.java
src\BrokenSyntax.java:3: error: ';' expected
        System.out.println("semicolon missing")
                                               ^

파일과 3번째 줄이 표시되고 컴파일러가 예상한 기호가 나옵니다.

세미콜론을 추가한 뒤 다시 컴파일합니다.

컴파일에 실패한 상태에서는 새 BrokenSyntax.class가 만들어지지 않습니다.

HTML 다이어그램: /docs/java/ch1/ch1-4/2.html

클래스 탐색 오류: 컴파일 결과를 못 찾음

Hello를 정상 컴파일한 뒤 클래스 경로를 빼고 실행합니다.

javac -d out src/Hello.java
java Hello
Error: Could not find or load main class Hello
Caused by: java.lang.ClassNotFoundException: Hello

out/Hello.class는 존재하지만 현재 폴더에서 찾았기 때문에 실패했습니다.

탐색 시작 폴더를 고칩니다.

java -cp out Hello

이 오류에서는 소스 코드를 고칠 필요가 없습니다.

컴파일 결과의 위치와 실행 명령을 고쳐야 합니다.

HTML 다이어그램: /docs/java/ch1/ch1-4/3.html

실행 중 오류: main에 들어간 뒤 실패

다음 파일은 문법상 올바르므로 컴파일됩니다.

하지만 정수를 0으로 나누는 문장을 실행할 때 더 진행할 수 없습니다.

src/RuntimeFailure.java — 일부러 실패하는 파일
public class RuntimeFailure {
    public static void main(String[] args) {
        System.out.println("before");
        System.out.println(10 / 0);
        System.out.println("after");
    }
}
javac -d out src/RuntimeFailure.java
java -cp out RuntimeFailure
before
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at RuntimeFailure.main(RuntimeFailure.java:4)

before가 출력됐으므로 JVM은 클래스를 찾고 main에도 진입했습니다.

마지막 줄의 파일명과 줄 번호는 실패한 문장을 가리킵니다.

after는 오류 뒤에 있으므로 실행되지 않습니다.

예외의 종류와 복구 방법은 ch12에서 배웁니다.

지금은 컴파일 오류와 달리 .class가 정상 생성됐고 실행 도중 실패했다는 점만 구분합니다.

HTML 다이어그램: /docs/java/ch1/ch1-4/4.html

이름 오류도 단계가 다르다

공개 클래스와 파일 이름이 다르면 컴파일 단계에서 실패합니다.

src/WrongName.java — 일부러 실패하는 파일
public class DifferentName {
    public static void main(String[] args) {
        System.out.println("not compiled");
    }
}

반대로 클래스는 컴파일됐지만 실행 가능한 main이 없으면 실행 단계에서 시작점을 찾지 못합니다.

src/NoMain.java — 컴파일은 되는 파일
public class NoMain {
    public static void print() {
        System.out.println("no entry point");
    }
}

print는 일반 메서드이고 자동으로 실행되지 않습니다.

java -cp out NoMainmain을 찾을 수 없다는 메시지를 냅니다.


오류를 읽는 순서

  1. 실행한 명령이 javac인지 java인지 확인합니다.
  2. 첫 오류의 종류와 메시지를 읽습니다.
  3. 표시된 파일과 줄을 찾습니다.
  4. 그 줄만 보지 말고 바로 앞의 괄호·중괄호·세미콜론도 확인합니다.
  5. 하나를 고친 뒤 같은 명령을 다시 실행합니다.

뒤에 이어지는 수십 개 오류가 첫 문법 오류 때문에 생길 수 있습니다.

한꺼번에 모든 줄을 바꾸지 말고 첫 오류부터 처리합니다.


연습 문제

다음 증상을 컴파일, 클래스 탐색, 실행 중 오류로 분류하고 첫 확인 대상을 적으세요.

  • ';' expected
  • ClassNotFoundException: Hello
  • ArithmeticException: / by zero
  • 파일을 수정했는데 이전 문장이 출력됨

마지막 증상은 오류 메시지가 없지만 오래된 .class를 실행한 경우입니다.

소스를 저장한 뒤 javac를 다시 실행했는지 확인합니다.