Перейти к основному содержимому

Ошибка компиляции «Не удается найти символ»

· 7 мин. чтения

1. Обзор

В этом руководстве мы рассмотрим, что такое ошибки компиляции, а затем конкретно объясним, что такое ошибка «не удается найти символ» и чем она вызвана.

2. Ошибки времени компиляции

Во время компиляции компилятор анализирует и проверяет код на множество вещей; ссылочные типы, приведения типов и объявления методов, и это лишь некоторые из них. Эта часть процесса компиляции важна, так как на этом этапе мы получим ошибку компиляции.

По сути, существует три типа ошибок времени компиляции:

  • У нас могут быть синтаксические ошибки . Одна из самых распространенных ошибок, которую может сделать любой программист, — забыть поставить точку с запятой в конце инструкции; некоторые другие забывают об импорте, не соответствуют скобкам или опускают оператор возврата.
  • Далее следуют ошибки проверки типов. Это процесс проверки безопасности типов в нашем коде. С помощью этой проверки мы удостоверяемся, что у нас есть согласованные типы выражений. Например, если мы определяем переменную типа int , мы никогда не должны присваивать ей двойное или строковое значение .
  • При этом существует вероятность того, что компилятор выйдет из строя . Это очень редко, но может случиться. В этом случае полезно знать, что наш код может быть не проблемой, а скорее внешней проблемой.

3. Ошибка «не удается найти символ»

Ошибка «не удается найти символ» возникает в основном, когда мы пытаемся использовать переменную, которая не определена или не объявлена в нашей программе.

Когда наш код компилируется, компилятору необходимо проверить все имеющиеся у нас идентификаторы. Ошибка «не удается найти символ» означает, что мы ссылаемся на что-то, о чем компилятор не знает .

3.1. Что может вызвать ошибку «не удается найти символ» ?

На самом деле есть только одна причина: компилятору не удалось найти определение переменной, на которую мы пытаемся сослаться.

Но, есть много причин, почему это происходит. Чтобы понять почему, давайте вспомним, из чего состоит код Java.

Наш исходный код Java состоит из:

  • Ключевые слова: истина, ложь, класс, пока
  • Литералы: числа и текст
  • Операторы и другие небуквенно-цифровые символы: -, /, +, =, {
  • Идентификаторы: main , Reader , i , toString и т. д.
  • Комментарии и пробелы

4. Орфографическая ошибка

Наиболее распространенные проблемы связаны с орфографией. Если мы вспомним, что все идентификаторы Java чувствительны к регистру, мы увидим, что:

  • StringBuilder
  • stringBuilder
  • String_Builder

все они будут разными способами неправильно ссылаться на класс StringBuilder .

5. Область действия экземпляра

Эта ошибка также может быть вызвана использованием чего-то, что было объявлено вне области действия класса.

Например, предположим, что у нас есть класс Article , который вызывает метод generateId :

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();
}
}

При такой настройке компилятор выдаст ошибку «не удается найти символ» для generateId в строке 7 фрагмента статьи . Причина в том, что синтаксис строки 7 подразумевает, что метод generateId объявлен в статье .

Как и во всех зрелых языках, существует несколько способов решения этой проблемы. Но одним из способов было бы создать IdGenerator в классе Article , а затем вызвать метод:

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
}
}

Мы решаем эту проблему, объявляя переменную text типа 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 , которого нет.

На самом деле, есть метод получения , который мы можем использовать вместо этого:

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)
}

И так забывая новое ключевое слово как в:

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

9. Импорт пакетов и классов

Другая проблема заключается в том, что вы забыли импортировать класс или пакет. Например, используя объект List без импорта java.util.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 date = new Date();
int year, month, day;

Чтобы получить год, месяц или день для java.util.Date , нам также нужно импортировать класс Calendar и извлечь оттуда информацию.

Простой вызов getDate() из java.util.Date не сработает:

...
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. Заключение

Компиляторы работают по фиксированному набору правил, зависящих от языка. Если код не соответствует этим правилам, компилятор не может выполнить процесс преобразования, что приводит к ошибке компиляции. Когда мы сталкиваемся с ошибкой компиляции «Не удается найти символ», важно определить причину.

Из сообщения об ошибке мы можем найти строку кода, в которой возникает ошибка, и какой элемент неверен. Знание наиболее распространенных проблем, вызывающих эту ошибку, сделает ее решение очень простым и быстрым.