Code Fix

上級

Map と HashMap を両方importする理由

インターフェースと実装クラスは別物です。受け口を広く、実体を具体的にという原則を扱います。

エラーメッセージの読み方

Main.java:5: error: cannot find symbol
Main.java
ファイル名
5
行番号 — javacが異常に気づいた位置。原因の行とは限りません
error
種別 — コンパイルエラー。実行まで到達しません
cannot find symbol
内容 — javacが期待していたもの、または見つけられなかったもの

このエラーが出る典型パターン

パターン1

 1  import java.util.List   ;
                        ^
 2  
 3  public class Main {
 4      public static void main(String[] args) {
 5          Map<String, Integer> m = new HashMap<>();
 6          m.put("a", 1);
 7          System.out.println(m.get("a"));
 8      }
 9  }
Main.java:5: error: cannot find symbol symbol: class Map

MapとHashMapは別クラスなので両方importが要ります。java.util.* でまとめて取り込めます。

直し方: List を * にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  import java.util.ArrayList;
 2  import java.util.List;
 3  
 4  public class Main {
 5      public static void main(String[] args) {
 6          List<String> list = new List      <>();
                                         ^
 7          list.add("a");
 8          System.out.println(list);
 9      }
10  }
Main.java:6: error: List is abstract; cannot be instantiated

Listはインターフェースなのでnewできません。受け口をインターフェース、実体を具象クラスにするのが定石です。

直し方: List を ArrayList にします。

この問題を解いてみる →

パターン3

 1  import java.util.*;
 2  
 3  public class Main {
 4      public static void main(String[] args) {
 5          Map<String, List<Integer>> m = new HashMap<>();
 6          m.put("a", new ArrayList()  );
                               ^
 7          System.out.println(m);
 8      }
 9  }
警告: unchecked conversion(コンパイルは通りますが型安全が失われます)

ダイヤモンド演算子を省くと生の型になり、型チェックが効かなくなります。<> を書くのが基本です。

直し方: new ArrayList() を new ArrayList<>() にします。

この問題を解いてみる →

パターン4

 1  import java.util.HashSet     ;
                           ^
 2  
 3  public class Main {
 4      public static void main(String[] args) {
 5          Set<Integer> s = new HashSet<>();
 6          s.add(1);
 7          System.out.println(s);
 8      }
 9  }
Main.java:5: error: cannot find symbol symbol: class Set

SetとHashSetは別クラスです。両方使うにはimport java.util.*; でまとめて取り込むのが簡単です。

直し方: HashSet を * にします。

この問題を解いてみる →

パターン5

 1  import java.util.ArrayList;
 2  import java.util.List             ;
                             ^
 3  
 4  public class Main {
 5      public static void main(String[] args) {
 6          List<Integer> list = new ArrayList<>(List.of(3, 1, 2));
 7          Collections.sort(list);
 8          System.out.println(list);
 9      }
10  }
Main.java:6: error: cannot find symbol symbol: variable Collections

ArrayListだけimportしても、ListやCollectionsは別途importが必要です。java.util.* でまとめて取り込みます。

直し方: List を * にします。

この問題を解いてみる →

よくある誤解

IDEの自動importがHashMapだけを足すことがあります。Mapが足りないまま残るので、エラーが消えません。

実務での勘所

Mapを受け口にしてHashMapを実装として使う書き方の実用上のメリットは、後から実装を差し替えやすいことです。順序を保持したくなればLinkedHashMapに、キー順にソートしたくなればTreeMapに、右辺を書き換えるだけで済みます。変数の型をMapのままにしておけば、その変数を使っている残りのコードは一切書き換える必要がありません。最初からHashMap型の変数として書いてしまうと、後からこの種の差し替えをするときに使用箇所すべての型を書き換える手間が発生します。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)