1. Общ преглед
В този урок ще разгледаме какво представляват грешките при компилацията и след това конкретно ще обясним каква е грешката „не мога да намеря символ“ и как тя е причинена.
2. Компилиране на грешки във времето
По време на компилацията компилаторът анализира и проверява кода за множество неща; референтни типове, отливки на типове и декларации на методи, за да назовем само няколко. Тази част от процеса на компилация е важна, тъй като по време на тази фаза ще получим грешка при компилацията.
По принцип има три вида грешки по време на компилация:
- Може да имаме синтаксични грешки . Една от най-често срещаните грешки, които всеки програмист може да направи, е да забрави да сложи точка и запетая в края на изявлението; някои други забравят импортирането, несъответстващите скоби или пропускат оператора return
- След това има грешки при проверка на типа. Това е процес на проверка на безопасността на типа в нашия код. С тази проверка се уверяваме, че имаме последователни типове изрази. Например, ако дефинираме променлива от тип int , никога не трябва да й присвояваме двойна или String стойност
- Междувременно има вероятност компилаторът да се срине . Това е много рядко, но може да се случи. В този случай е добре да знаете, че нашият код може да не е проблем, но че е по-скоро външен проблем
3. Грешка „Не мога да намеря символ“
Грешката „не мога да намеря символ“ се появява главно, когато се опитваме да използваме променлива, която не е дефинирана или декларирана в нашата програма.
Когато нашият код се компилира, компилаторът трябва да провери всички идентификатори, които имаме. Грешката „не мога да намеря символ“ означава, че имаме предвид нещо, за което компилаторът не знае .
3.1. Какво може да причини грешка „не мога да намеря символ“ ?
Всъщност има само една причина: Компилаторът не можа да намери дефиницията на променлива, на която се опитваме да се позовем.
Но има много причини, поради които това се случва. За да ни помогнете да разберем защо, нека си припомним от какво се състои Java кода.
Нашият изходен код на Java се състои от:
- Ключови думи: true, false, class, while
- Литерали: цифри и текст
- Оператори и други небуквено-цифрови символи: -, /, +, =, {
- Идентификатори: main , Reader , i , toString и др.
- Коментари и интервали
4. Погрешно изписване
Най-често срещаните проблеми са свързани с правописа. Ако си припомним, че всички Java идентификатори са чувствителни към малки и големи букви, можем да видим, че:
- StringBiulder
- stringBuilder
- String_Builder
всички биха били различни начини за неправилно позоваване на класа StringBuilder .
5. Обхват на инстанцията
Тази грешка може да бъде причинена и при използване на нещо, което е декларирано извън обхвата на класа.
Например, нека кажем, че имаме член клас, който нарича 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(); } }
С тази настройка компилаторът ще даде грешка „не мога да намеря символ“ за createId на ред 7 на фрагмента Article . Причината е, че синтаксиса на линия 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. Недефинирани променливи
Понякога забравяме да декларираме променливата. Както можем да видим от фрагмента по-долу, ние се опитваме да манипулираме променливата, която не сме декларирали, в този случай текст :
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 texts; public Article(int length) { this.length = length; } // getters and setters }
Сега, ако се опитаме да се позовем на текстовото поле на статията, сякаш е метод:
Article article = new Article(300); List texts = article.texts();
тогава ще видим грешката.
That's because the compiler is looking for a method called texts, which there isn't one.
Actually, there's a getter method that we can use instead:
Article article = new Article(300); List texts = article.getTexts();
Mistakenly operating on an array rather than an array element is also an issue:
for (String text : texts) { String firstLetter = texts.charAt(0); // it should be text.charAt(0) }
And so is forgetting the new keyword as in:
String s = String(); // should be 'new String()'
9. Package and Class Imports
Another problem is forgetting to import the class or package. For example, using a List object without importing java.util.List:
// missing import statement: // import java.util.List public class Article { private int length; private long id; private List texts; <-- error! public Article(int length) { this.length = length; } }
This code would not compile since the program doesn't know what List is.
10. Wrong Imports
Importing the wrong type, due to IDE completion or auto-correction is also a common issue.
Think of the situation when we want to use dates in Java. A lot of times we could import a wrong Date class, which doesn't provide methods and functionalities as other date classes that we might need:
Date date = new Date(); int year, month, day;
To get the year, month, or day for java.util.Date, we also need to import Calendar class and extract the information from there.
Simply invoking getDate() from java.util.Date won't work:
... date.getDay(); date.getMonth(); date.getYear();
Instead, we use the Calendar object:
... 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);
However, if we have imported the LocalDate class, we wouldn't need additional code that provides us the information we need:
... LocalDate localDate=date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); year = localDate.getYear(); month = localDate.getMonthValue(); day = localDate.getDayOfMonth();
11. Conclusion
Компилаторите работят по фиксиран набор от правила, които са специфични за езика. Ако кодът не се придържа към тези правила, компилаторът не може да извърши процес на преобразуване, което води до грешка в компилацията. Когато се сблъскаме с грешката при компилацията „Не мога да намеря символ“, ключът е да се идентифицира причината.
От съобщението за грешка можем да намерим реда на кода, където възниква грешката и кой елемент е грешен. Познаването на най-често срещаните проблеми, причиняващи тази грешка, ще направи решаването му много лесно и бързо.