HOWTO · Java

Java에서 `<identifier> expected` 오류를 수정하는 방법

javac가 보고하는 `<identifier> expected`의 의미와 이름이 없는 매개변수, 잘못 배치된 문장, 잘못된 try-with-resources 구문을 수정하는 방법을 설명합니다.

이 페이지의 내용

Java 컴파일러는 변수, 메서드 또는 클래스 이름처럼 문법상 이름이 필요한 위치에서 토큰을 만나면 <identifier> expected를 보고합니다. javac가 표시한 줄과 커서 바로 앞의 선언 또는 문장을 확인하세요. 매개변수의 형식이나 이름이 빠졌거나, 클래스 본문에 실행 문장이 있거나, 리소스 선언이 잘못된 경우가 흔한 원인입니다.

<identifier> expected 진단 이해하기

식별자는 Java 프로그램 요소의 이름입니다. Java 식별자에는 문자, 숫자, $, _를 포함할 수 있지만 숫자로 시작하거나 예약어일 수는 없습니다. 매개변수 선언에는 형식과 식별자가 모두 필요합니다(예: int count). 클래스 본문에는 필드와 초기화 블록을 둘 수 있지만 독립적인 대입이나 메서드 호출은 둘 수 없습니다.

javac는 문법을 더 진행할 수 없는 위치를 보고하며, 그 위치가 항상 근본 원인은 아닙니다. 표시된 토큰을 바꾸기 전에 앞의 중괄호, 세미콜론, 쉼표, 괄호를 확인하세요. 첫 번째 진단을 수정한 뒤 다시 컴파일하세요. 뒤의 메시지는 같은 구문 오류에서 파생될 수 있습니다.

매개변수 형식 또는 이름 누락 수정하기

모든 메서드 매개변수에는 데이터 형식 뒤에 변수 이름이 와야 합니다. 다음 선언에는 형식이 없습니다.

public class Demo {
  static int square(x) {
    return x * x;
  }
}

이 잘못된 형식을 javac로 컴파일하면 다음과 비슷한 진단이 표시됩니다(JDK에 따라 줄 번호와 커서는 달라질 수 있습니다).

Demo.java:2: error: <identifier> expected
  static int square(x) {
                   ^
1 error

수정된 선언은 x 앞에 int를 제공합니다.

public class Demo {
  static int square(int x) {
    return x * x;
  }

  public static void main(String[] args) {
    System.out.println(square(10));
  }
}

javac Demo.java로 컴파일하고 java Demo로 실행하면 출력은 다음과 같습니다.

100

반대의 실수도 실패합니다. static int square(int)에는 형식이 있지만 매개변수 식별자가 없습니다. 이름을 추가하고 메서드 본문에서도 같은 이름을 사용하세요. classreturn 같은 예약어 대신 value처럼 유효한 식별자를 선택하세요.

예를 들어 static int square(int)에서는 javac가 매개변수 이름을 기대하므로 같은 진단이 발생합니다.

Demo.java:2: error: <identifier> expected
  static int square(int) {
                       ^
1 error

실행 문장을 메서드 또는 초기화 블록으로 옮기기

필드는 클래스에 직접 선언할 수 있지만 대입과 메서드 호출은 메서드, 생성자 또는 초기화 블록 안에 있어야 합니다. 다음 클래스 본문 코드는 잘못되었습니다.

public class Demo {
  private String name;
  name = "Naruto";
  System.out.println(name);
}

컴파일러는 클래스 본문 문법이 선언이나 블록을 기대하는 토큰 위치에서 오류를 보고합니다.

Demo.java:3: error: <identifier> expected
  name = "Naruto";
      ^
Demo.java:4: error: <identifier> expected
  System.out.println(name);
                    ^
3 errors

실행 문장을 메서드에 넣고 main에서 호출하세요.

public class Demo {
  private String name;

  void print() {
    name = "Naruto";
    System.out.println(name);
  }

  public static void main(String[] args) {
    Demo demo = new Demo();
    demo.print();
  }
}

성공한 출력은 다음과 같습니다.

Naruto

대입이 필드 초기화 목적이라면 인스턴스 초기화 블록({ name = "Naruto"; })도 유효합니다. 필드 초기화 식으로 private String name = "Naruto";를 사용할 수도 있지만 초기화 블록이나 메서드 밖의 독립적인 메서드 호출은 허용되지 않습니다.

try-with-resources

리소스 지정부에는 BufferedReader reader = ... 같은 선언이나 이미 초기화된 final 또는 사실상 final 변수에 대한 참조를 사용할 수 있습니다. 지정부에서 변수에 새 리소스를 대입하는 것은 선언 형식이 아닙니다.

import java.io.BufferedReader;
import java.io.StringReader;

public class Demo {
  public static void main(String[] args) throws Exception {
    BufferedReader reader = null;
    try (reader = new BufferedReader(new StringReader("Java"))) {
      System.out.println(reader.readLine());
    }
  }
}

테스트한 JDK에서는 이미 선언된 reader에 대한 대입이 리소스 지정부에서 거부됩니다.

Demo.java:7: error: the try-with-resources resource must either be a variable declaration or an expression denoting a reference to a final or effectively final variable
    try (reader = new BufferedReader(new StringReader("Java"))) {
                ^
1 error

대신 try 안에서 리소스를 선언하세요.

import java.io.BufferedReader;
import java.io.StringReader;

public class Demo {
  public static void main(String[] args) throws Exception {
    try (BufferedReader reader = new BufferedReader(new StringReader("Java"))) {
      System.out.println(reader.readLine());
    }
  }
}

출력은 다음과 같습니다.

Java

수정된 형식은 try 블록 끝에서 reader를 자동으로 닫습니다. 이후 코드에서 값이 필요하면 리소스가 열려 있을 때 필요한 값을 복사하고, 블록 뒤에서 닫힌 리소스를 사용하지 마세요.

다시 컴파일하기 전 체크리스트

<identifier> expected가 계속되면 다음 경계를 순서대로 확인하세요.

  1. 모든 매개변수에 형식과 이름이 있는지 확인합니다.
  2. 이름이 예약어가 아니고 숫자로 시작하지 않으며 의도한 대소문자인지 확인합니다.
  3. 대입, 메서드 호출 등 실행 문장을 메서드, 생성자 또는 초기화 블록으로 옮깁니다.
  4. 앞선 줄의 중괄호와 구두점을 검사합니다.
  5. try-with-resources에서는 선언 또는 미리 초기화한 사실상 final 리소스를 사용합니다.

이 규칙은 안정적인 Java 문법이며 Java SE 27을 포함한 현재 JDK 릴리스에 적용됩니다. 컴파일러 버전에 따라 진단의 정확한 문구나 줄 번호가 달라질 수 있으므로 메시지와 커서는 주변 문법을 알려 주는 단서로 보고 원래 오타를 반드시 가리킨다고 단정하지 마세요.