1. 개요

이 사용방법(예제)에서는 컴파일 오류가 무엇인지 검토합니다. 그런 다음 " 기호를 찾을 수 없습니다 " 오류와 그 원인에 대해 구체적으로 설명하겠습니다 .

2. 컴파일 시간 오류

컴파일하는 동안 컴파일러는 참조 유형, 유형 캐스트 ​​및 메서드 선언과 같은 다양한 항목에 대한 코드를 분석하고 확인합니다. 컴파일 프로세스의 이 부분은 중요합니다. 이 단계에서 컴파일 오류가 발생하기 때문입니다.

기본적으로 컴파일 타임 오류에는 세 가지 유형이 있습니다.

  • 구문 오류가 있을 수 있습니다 . 프로그래머가 저지를 수 있는 가장 일반적인 실수 중 하나는 명령문 끝에 세미콜론을 넣는 것을 잊는 것입니다. 다른 실수로는 수입품을 잊어버리거나, 괄호가 일치하지 않거나, return 문을 생략하는 등이 있습니다.
  • 다음으로 유형 검사 오류가 있습니다 . 이것은 코드에서 유형 안전성을 확인하는 프로세스입니다. 이 검사를 통해 일관된 유형의 표현식이 있는지 확인하고 있습니다. 예를 들어 int 유형의 변수를 정의하는 경우 double 또는 String 값을 할당해서는 안 됩니다 .
  • 마지막으로 컴파일러가 충돌할 가능성이 있습니다 . 이것은 매우 드물지만 발생할 수 있습니다. 이 경우 코드가 문제가 아니라 외부 문제일 수 있음을 아는 것이 좋습니다.

3. "기호를 찾을 수 없습니다" 오류

" 기호를 찾을 수 없습니다 " 오류는 프로그램에서 정의 또는 선언되지 않은 변수를 사용하려고 할 때 주로 발생합니다.

코드를 컴파일할 때 컴파일러는 우리가 가지고 있는 모든 식별자를 확인해야 합니다. 오류 " 기호를 찾을 수 없습니다 "는 컴파일러가 알지 못하는 것을 참조하고 있음을 의미합니다 .

3.1. "기호를 찾을 수 없음" 오류 의 원인은 무엇입니까 ?

정말 단 하나의 원인이 있습니다. 컴파일러는 참조하려는 변수의 정의를 찾을 수 없습니다.

그러나 이런 일이 발생하는 데는 여러 가지 이유가 있습니다. 이유를 이해하는 데 도움이 되도록 Java 소스 코드가 무엇으로 구성되어 있는지 상기해 봅시다.

  • 키워드: true, false, class, while
  • 리터럴: 숫자 및 텍스트
  • 연산자 및 기타 영숫자가 아닌 토큰: -, /, +, =, {
  • 식별자: main , Reader , i , toString
  • 어노테이션 및 공백

4. Custom법 오류

가장 일반적인 문제는 모두 Custom법과 관련이 있습니다. 모든 Java 식별자가 대소문자를 구분한다는 사실을 기억한다면 다음은 모두 StringBuilder 클래스 를 잘못 참조하는 다른 방법임을 알 수 있습니다 .

  • StringBiulder
  • stringBuilder
  • String_Builder

5. 인스턴스 범위

이 오류는 클래스 범위 외부에서 선언된 항목을 사용할 때도 발생할 수 있습니다.

예를 들어 다음과 같이 generateId  메서드를 호출하는 Article 클래스가 있다고 가정해 보겠습니다 .

public class Article {
    private int length;
    private long id;

    public Article(int length) {
        this.length = length;
        this.id = generateId();
    }
}

그러나 별도의 클래스에서 generateId 메서드를 선언합니다 .

public class IdGenerator {
    public long generateId() {
        Random random = new Random();
        return random.nextInt();
    }
}

이 설정을 사용하면 컴파일러는 기사 스니펫 의 7행에서 generateId 에 대해 " 기호를 찾을 수 없음 " 오류를 제공합니다 . 이는 7행의 구문이 Article 에서 generateId 메소드가 선언되었음을  의미하기 때문입니다 .

모든 성숙한 언어와 마찬가지로 이 문제를 해결하는 방법은 여러 가지가 있지만 한 가지 방법은 Article 클래스 에서 IdGenerator를 구성한 다음 메서드를 호출하는 것입니다.

public class Article {
    private int length;
    private long id;

    public Article(int length) {
        this.length = length;
        this.id = new IdGenerator().generateId();
    }
}

6. 정의되지 않은 변수

때때로 우리는 변수를 선언하는 것을 잊습니다. 아래 스니펫에서 볼 수 있듯이 선언하지 않은 변수(이 경우 text ) 를 조작하려고 합니다 .

public class Article {
    private int length;

    // ...

    public void setText(String newText) {
        this.text = newText; // text variable was never defined
    }
}

String 유형의 변수 텍스트를 선언하여 이 문제를 해결합니다 .

public class Article {
    private int length;
    private String text;
    // ...

    public void setText(String newText) {
        this.text = newText;
    }
}

7. 변수 범위

변수 선언이 사용하려고 시도한 시점에서 범위를 벗어나면 컴파일 중에 오류가 발생합니다. 이것은 일반적으로 루프로 작업할 때 발생합니다.

루프 내부의 변수는 루프 외부에서 액세스할 수 없습니다.

public boolean findLetterB(String text) {
    for (int i=0; i < text.length(); i++) {
        Character character = text.charAt(i);
        if (String.valueOf(character).equals("b")) {
            return true;
        }
        return false;
    }

    if (character == "a") {  // <-- error!
        ...
    }
}

문자를 더 검사해야 하는 경우 if 문 for 루프 안에 들어가야 합니다 .

public boolean findLetterB(String text) {
    for (int i = 0; i < text.length(); i++) {
        Character character = text.charAt(i);
        if (String.valueOf(character).equals("b")) {
            return true;
        } else if (String.valueOf(character).equals("a")) {
            ...
        }
        return false;
    }
}

8. 메소드 또는 필드의 잘못된 사용

필드를 메서드로 사용하거나 그 반대의 경우에도 " 기호를 찾을 수 없습니다 " 오류가 발생합니다.

public class Article {
    private int length;
    private long id;
    private List<String> texts;

    public Article(int length) {
        this.length = length;
    }
    // getters and setters
}

기사의 텍스트 필드를 메소드인 것처럼 참조하려고 하면 다음 과 같습니다.

Article article = new Article(300);
List<String> texts = article.texts();

그러면 오류가 표시됩니다.

이는 컴파일러가 texts 라는 메서드를 찾고 있지만 메서드가 없기 때문입니다.

실제로 대신 사용할 수 있는 getter 메서드 가 있습니다 .

Article article = new Article(300);
List<String> texts = article.getTexts();

배열 요소가 아닌 배열에서 실수로 작동하는 것도 문제입니다.

for (String text : texts) {
    String firstLetter = texts.charAt(0); // it should be text.charAt(0)
}

그래서 new 키워드를 잊고 있습니다.

String s = String(); // should be 'new String()'

9. 패키지 및 클래스 가져오기

또 다른 문제는 java.util.List를  가져오지 않고  List 객체를 사용하는 것과 같이 클래스나 패키지를 가져오는 것을 잊는 것입니다 .

// missing import statement: 
// import java.util.List

public class Article {
    private int length;
    private long id;
    private List<String> texts;  <-- error!
    public Article(int length) {
        this.length = length;
    }
}

프로그램이 List 가 무엇인지 모르기 때문에 이 코드는 컴파일되지 않습니다 .

10. 잘못된 수입

IDE 완성 또는 자동 수정으로 인해 잘못된 유형을 가져오는 것도 일반적인 문제입니다.

Java에서 날짜를 사용하려는 시나리오를 생각해 보십시오. 필요한 다른 날짜 클래스와 동일한 메서드 및 기능을 제공하지 않는 잘못된 날짜 클래스를 가져올 수 있는 경우가 많습니다 .

Date date = new Date();
int year, month, day;

java.util.Date 에 대한 연도, 월 또는 일을 얻으려면 Calendar 클래스를 가져오고 거기에서 정보를 추출 해야 합니다 .

단순히 java.util.Date 에서 getDate()를 호출하면 작동하지 않습니다.

...
date.getDay();
date.getMonth();
date.getYear();

대신 Calendar 개체를 사용합니다.

...
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Europe/Paris"));
cal.setTime(date);
year = cal.get(Calendar.YEAR);
month = cal.get(Calendar.MONTH);
day = cal.get(Calendar.DAY_OF_MONTH);

그러나 LocalDate 클래스를 가져온 경우 필요한 정보를 제공하기 위해 추가 코드가 필요하지 않습니다.

...
LocalDate localDate=date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
year = localDate.getYear();
month = localDate.getMonthValue();
day = localDate.getDayOfMonth();

11. 결론

컴파일러는 언어별 고정된 규칙 집합에 따라 작동합니다. 코드가 이러한 규칙을 준수하지 않으면 컴파일러는 변환 프로세스를 수행할 수 없으므로 컴파일 오류가 발생합니다. " 기호를 찾을 수 없습니다 " 컴파일 오류가 발생하면 원인을 식별하는 것이 핵심입니다.

오류 메시지에서 오류가 발생한 코드 줄과 잘못된 요소를 찾을 수 있습니다. 이 오류를 일으키는 가장 일반적인 문제를 알면 빠르고 쉽게 해결할 수 있습니다.

res – REST with Spring (eBook) (everywhere)