1. 概要

このチュートリアルでは、コンパイルエラーとは何かを確認してから、「シンボルが見つかりません」エラーとは何か、およびその原因について具体的に説明します。

2. コンパイル時エラー

コンパイル中に、コンパイラーはコードを分析して検証します。 いくつか例を挙げると、参照型、型キャスト、およびメソッド宣言。 このフェーズではコンパイルエラーが発生するため、コンパイルプロセスのこの部分は重要です。

基本的に、コンパイル時エラーには次の3つのタイプがあります。

  • 構文エラーが発生する可能性があります。 プログラマーが犯す可能性のある最も一般的な間違いの1つは、ステートメントの最後にセミコロンを付けるのを忘れることです。 他のいくつかは、インポートを忘れているか、括弧が一致していないか、returnステートメントを省略しています
  • 次に、 タイプチェックエラーがあります。これは、コードでタイプの安全性を検証するプロセスです。 このチェックにより、一貫したタイプの式があることを確認しています。 たとえば、タイプ int の変数を定義する場合、doubleまたはString値を割り当てないでください。
  • その間、コンパイラがクラッシュする可能性があります。 これは非常にまれですが、発生する可能性があります。 この場合、コードは問題ではないかもしれませんが、むしろ外部の問題であることを知っておくとよいでしょう。

3. 「シンボルが見つかりません」エラー

「シンボルが見つかりません」エラーは、主に、プログラムで定義または宣言されていない変数を使用しようとしたときに発生します。

コードをコンパイルするとき、コンパイラは私たちが持っているすべての識別子を検証する必要があります。 エラー「シンボルが見つかりません」は、コンパイラがについて知らないものを参照していることを意味します。

3.1. 「シンボルが見つかりません」エラーの原因は何ですか?

実際、原因は1つだけです。 コンパイラーは、参照しようとしている変数の定義を見つけることができませんでした。

しかし、これが起こる理由はたくさんあります。 その理由を理解するために、Javaコードが何で構成されているかを思い出してみましょう。

Javaソースコードは次のもので構成されています。

  • キーワード: true、false、class、while
  • リテラル:数字とテキスト
  • 演算子およびその他の英数字以外のトークン:-、/、+、=、{
  • 識別子: main Reader i toStringなど。
  • コメントと空白

4. スペルミス

最も一般的な問題はすべてスペル関連です。 すべてのJava識別子で大文字と小文字が区別されることを思い出すと、次のことがわかります。

  • StringBiulder
  • stringBuilder
  • String_Builder

StringBuilderクラスを誤って参照する方法はすべて異なります。

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行目の構文は、generateIdメソッドがArticleで宣言されていることを意味しているためです。

すべての成熟した言語と同様に、この問題に対処する方法は複数あります。 ただし、1つの方法は、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の変数textを宣言することにより、この問題を解決します。

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の texts フィールドを、メソッドであるかのように参照しようとすると、次のようになります。

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

そして、次のように新しいキーワードを忘れています。

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

9. パッケージとクラスのインポート

別の問題は、クラスまたはパッケージのインポートを忘れることです。たとえば、 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() from 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. 結論

コンパイラは、言語固有の固定されたルールのセットで動作します。 コードがこれらの規則に従わない場合、コンパイラーは変換プロセスを実行できず、コンパイルエラーが発生します。 「シンボルが見つかりません」というコンパイルエラーが発生した場合、重要なのは原因を特定することです。

エラーメッセージから、エラーが発生したコード行と、どの要素が間違っているかを見つけることができます。 このエラーの原因となる最も一般的な問題を知っていると、非常に簡単かつ迅速に解決できます。