このページではJavaの練習問題、特に知識が問われる問題をまとめて作成してみた。
Javaに対してどれくらい理解ができてきたかの試金石になるだろう。少々難しい部分もあるので、初心者の方はしっかり勉強してからトライしてみていただければと思う。
目次
Javaの練習問題:知識編
それでは早速、練習問題に取り掛かっていこう。
解答方法
入力値は問題で定められた規則に従い、正しく入力されるものとし、入力ミスなどは考慮しなくてよい。
練習問題1(java.ioパッケージ テキストファイル入出力)
テキストファイルに記載された内容を表示し、異なるファイルに出力するプログラムを作成しなさい
- 読み込むファイル名、出力するファイル名は、引数から取得するものとする。
- テキストファイルはUTF-8形式で記述されたものとする。
- 改行コードはCRLFを使用する。
実行例
java Main textA.txt textB.txt
入力ファイルの中身
1 2 3 4 5 6 |
Javaプログラムの実行結果 ABCDEFG 1234567890 あいうえお ABCDEFG 1234567890 |
出力例
1 2 3 4 5 6 |
Javaプログラムの実行結果 ABCDEFG 1234567890 あいうえお ABCDEFG 1234567890 |
練習問題2(java.ioパッケージ バイナリファイル入出力)
バイナリ形式のファイルを読み込み、異なるファイルに出力するプログラムを作成しなさい
ただし、読み込むファイル名、出力するファイル名は、引数から取得するものとする。
実行例
java Main imageA.png imageB.png
練習問題3(java.utilパッケージ Listの利用)
テキストファイルに記載された内容を1行ずつListに格納し、以下の処理を行うプログラムを作成しなさい。
- 1行目から順に出力する
- 最終行から逆順に1行目まで出力する
- 文字列「あいうえお」が格納されている行番号を出力する(先頭行を1行目と数える)
なお、テキストファイルの入力については以下の条件とする
- 読み込むファイル名、出力するファイル名は、引数から取得するものとする。
- テキストファイルはUTF-8形式で記述されたものとする。
- 改行コードはCRLFを使用する。
実行例
java Main textA.txt
入力ファイルの中身
1 2 3 4 5 6 |
Javaプログラムの実行結果 ABCDEFG 1234567890 あいうえお ABCDEFG 1234567890 |
Javaプログラムの実行結果出力例
1 2 3 4 5 6 7 8 9 10 11 |
ABCDEFG 1234567890 あいうえお ABCDEFG 1234567890 1234567890 ABCDEFG あいうえお 1234567890 ABCDEFG 3行目 |
練習問題4(java.utilパッケージ Mapの利用)
テキストファイルに記載された内容を1行ずつMapに格納し、以下の処理を行うプログラムを作成しなさい。
なお、テキストファイルの入力については以下の条件とする
- 読み込むファイル名、出力するファイル名は、引数から取得するものとする。
- テキストファイルはUTF-8形式で記述されたものとする。
- 改行コードはCRLFを使用する。
- 1行には、空白区切りで2つの文字列が記述されており、一つ目をキー、2つ目を値として、Mapに格納する。
処理内容
- すべてのキーと値を出力する
- キー「TOKYO」の値を出力する
実行例
java Main textA.txt
入力ファイルの中身
1 2 3 4 5 6 7 |
IBARAKI 水戸市 TOCHIGI 宇都宮市 GUNMA 前橋市 SAITAMA さいたま市 CHIBA 千葉市 TOKYO 東京(新宿区) KANAGAWA 横浜市 |
出力例
1 2 3 4 5 6 7 8 |
GUNMA : 前橋市 TOKYO : 東京(新宿区) CHIBA : 千葉市 IBARAKI : 水戸市 SAITAMA : さいたま市 KANAGAWA : 横浜市 TOCHIGI : 宇都宮市 TOKYO=>東京(新宿区) |
練習問題5(java.utilパッケージ Comparatorの利用)
問題4の入力に対して、以下の表示順序で出力するプログラムを作成しなさい。
出力順序
- キーの文字列順序(アルファベット辞書順)で出力する
- キー名の短い順とし、同じ長さの場合はアルファベット辞書順とする
実行例
java Main textA.txt
入力ファイルの中身
1 2 3 4 5 6 7 |
IBARAKI 水戸市 TOCHIGI 宇都宮市 GUNMA 前橋市 SAITAMA さいたま市 CHIBA 千葉市 TOKYO 東京(新宿区) KANAGAWA 横浜市 |
出力例1
1 2 3 4 5 6 7 |
CHIBA : 千葉市 GUNMA : 前橋市 IBARAKI : 水戸市 KANAGAWA : 横浜市 SAITAMA : さいたま市 TOCHIGI : 宇都宮市 TOKYO : 東京(新宿区) |
出力例2
1 2 3 4 5 6 7 |
CHIBA : 千葉市 GUNMA : 前橋市 TOKYO : 東京(新宿区) IBARAKI : 水戸市 SAITAMA : さいたま市 TOCHIGI : 宇都宮市 KANAGAWA : 横浜市 |
練習問題の解答
いかがだっただろうか? すんなり書けたという人も、なかなか難しかったという人もいるだろう。
ここからはJava練習問題の解答をお伝えする。できれば解いてから見てみていただきたい。
練習問題1 解答/解説
解答例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class Main { public static void main(String[] args) { try{ FileReader file = new FileReader(args[0]);//① BufferedReader buff = new BufferedReader(file); FileWriter writer = new FileWriter(args[1]);//② String text; while ((text = buff.readLine()) != null) { System.out.println(text); writer.write(text); writer.write("\r\n");//③ } file.close();//④ writer.close(); }catch(FileNotFoundException fnoe){//⑤ fnoe.printStackTrace(); }catch(IOException ioe){ //⑥ ioe.printStackTrace(); } } } |
- テキストファイルの読み込みには、FileReaderおよびBufferedReaderを利用する。
- テキストファイルの出力には、FileWriterを利用する。
- 改行コード「CRLF」を出力する場合は、プログラム中では「\r\n」を出力する。
- 入力ファイル、出力ファイル共に、最後にclose()を忘れてはならない。
- FileReaderのコンストラクタでは、入力ファイルが見つからない場合にFileNotFoundExceptionがThrowされる。
- readLine()メソッドでのファイルの読み込みや、write()メソッドでのファイル出力時のエラーは、IOExceptionがThrowされる。
javaによるファイル入出力の問題だ。
基本的には「ファイルを開く」「ファイルを読む、書き込む」「ファイルを閉じる」の順に実行しているだけだが、いくつか注意しなければならないポイントがある。
try/catchによる例外の捕捉
ファイルを取り扱う為のメソッドの多くは、あらかじめ例外が定義されており、try/catchでの例外処理を必要とする。
例外が発生するケースとしては
- 読み込むためのファイルが存在しない
- ファイルが開けない(ファイルのアクセス権など)
- ファイルが読めない(ディスクの不良など)
- ファイルに書き込めない(ディスクの空きが無いなど)
などが考えられる。
また、この問題では
- テキストファイルはUTF-8形式で記述されたものとする。
という指定を設けたが、読み込むファイルの形式が異なる場合には、一工夫必要だ。
例えば、SJIS形式のファイルの読み書きを行うのであれば、以下のような処理となる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class Main { public static void main(String[] args) { try{ ① InputStreamReader reader = new InputStreamReader(new FileInputStream(args[0]),"SJIS"); BufferedReader buff = new BufferedReader(reader); ② OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(args[1]),"SJIS"); String text; while ((text = buff.readLine()) != null) { System.out.println(text); writer.write(text); writer.write("\r\n"); } reader.close(); writer.close(); }catch(FileNotFoundException fnoe){ fnoe.printStackTrace(); }catch(IOException ioe){ ioe.printStackTrace(); } } } |
- FileReaderでは無くInputStreamReaderを使用するが、その際にファイルの保存形式の文字コードを指定する。
- FileWriterでは無くOutputStreamWriterを使用するが、その際にファイルの保存形式の文字コードを指定する。
この記述にすることで、SJIS形式のファイルの読み書きが可能となる。
Javaでは、様々な環境で実行されるプログラムに対応するため、基本はUTF-8でテキストデータを扱うものとし、必要に応じて文字コードの変換を行うことが出来るように文字コードの変換機能が用意されている。
ファイルの読み書きに限らず、文字化けが発生した際には、どの文字コードで作成されたデータなのか、どの文字コードで出力しているのかを整理しよう。
練習問題2 解答/解説
解答例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class Main { public static void main(String[] args) { try { ① FileInputStream fis = new FileInputStream(args[0]); ② FileOutputStream fos = new FileOutputStream(args[1]); int c = 0 ; while((c = fis.read()) != -1){ fos.write(c); } ③ fis.close(); fos.close(); }catch(FileNotFoundException fnoe){ fnoe.printStackTrace(); }catch(IOException ioe){ ioe.printStackTrace(); } } } |
- ファイルの読み込みには、FileInputStreamを利用する。
- ファイルの出力には、FileOutputStreamを利用する
- 入力ファイル、出力ファイル共に、最後にclose()を忘れてはならない。
バイナリファイルの取り扱いに関する問題だ。
恐らく、ファイルというとテキスト形式のファイルを思い浮かべる人も多いかも知れないが、コンピューター上で扱うファイルの多くは、人が目で見て読み取ることのできない、バイナリ形式のファイルだ。
テキスト形式のファイルというのは、そこに記載されているデータを人が読んで理解できるように表現する必要があるため、文字コードの変換などが必要だが、バイナリ形式の場合は、そもそも特定のプログラムでなければ読み取ることは出来ないので、プログラム中での扱いはあまり複雑なものにはならない。
しかし、画像ファイルやワープロ、表計算ソフトのファイルを読み取ってデータとして扱ったり、編集する場合には、そのファイル形式に応じたプログラム処理が必要となってくる。
その場合、処理も複雑になるが、そもそもファイルの構造は細かく把握しなければならないため、プログラムの難易度は大きく跳ね上がる事を覚悟しよう。
練習問題3 解答/解説
解答例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class Main { public static void main(String[] args) { try{ InputStreamReader reader = new InputStreamReader(new FileInputStream(args[0])); BufferedReader buff = new BufferedReader(reader); String text ; ① List<String> list = new ArrayList<String>(); while ((text = buff.readLine()) != null) { ② list.add(text); } reader.close(); for(String line : list){ System.out.println(line); } for(int index = list.size() - 1 ; -1 < index ; index --){ String line = list.get(index); System.out.println(line); } ③ int index = list.indexOf("あいうえお"); if(index != -1){ System.out.println((index + 1) + "行目"); } }catch(FileNotFoundException fnoe){ fnoe.printStackTrace(); }catch(IOException ioe){ ioe.printStackTrace(); } } } |
ファイル読み込み処理については、問題1と同様なので、説明を割愛する。
- Listはインターフェース定義のため、実体を生成する際にはArrayListを使用する。ArrayListは、いかなる型のオブジェクトも格納可能だが、型を明示する事で記述ミスを減らす。
- add()メソッドを使用して、要素を追加する。
- get()メソッドを使用して、指定の要素番号(0から数える)の要素を取得する。
- indexOf()メソッドを使用して、要素の先頭から最初に見つかった同一要素の要素番号を取得する。
Listの扱い方を確認する問題だ。
まず、java.util.Listはインターフェースとして定義されているため、実体を生成する事は出来ない。
標準で提供されているクラスでも、いくつかのクラスがListインターフェースを実装しているが、最も使い勝手がよく利用頻度が高いのがjava.util.ArrayListであろう。
ここでは、Listの中身に文字列を入れることがあらかじめはっきりしているため、宣言時には
List<String> list = new ArrayList<String>();
と、「<String>」と明記する事で、コンパイルの時点で誤った要素の追加を行う記述を発見できるようにしている。
単に
List list = new ArrayList ();
と記述しても、プログラムは問題なく動作するのだが、処理が複雑なプログラムになると、Listにどのような型のオブジェクトが入っているのかわからなくなり、プログラムの誤動作につながるような誤った記述を見逃してしまう可能性が高くなる。
このような型(<String>のような記述)の事を総称型と呼び、Javaでは様々なクラスで用いられている。
Eclipseなどの開発ツールを利用すると、型の明示が無い場合に警告表示されたりするが、余程のことが無ければ総称型の記述を怠らず、安全性の高いプログラムの作成を心掛けてもらいたい。
練習問題4 解答/解説
解答例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public class Main { public static void main(String[] args) { try{ InputStreamReader reader = new InputStreamReader(new FileInputStream(args[0])); BufferedReader buff = new BufferedReader(reader); String text ; ① Map<String,String> map = new HashMap<String,String>(); while ((text = buff.readLine()) != null) { String[] value = text.split(" "); ② map.put(value[0], value[1]); } reader.close(); ③ for(Map.Entry<String, String> e : map.entrySet()) { System.out.println(e.getKey() + " : " + e.getValue()); } String place = map.get("TOKYO"); if(place != null){ System.out.println("TOKYO=>" + place); } }catch(FileNotFoundException fnoe){ fnoe.printStackTrace(); }catch(IOException ioe){ ioe.printStackTrace(); } } } |
ファイル読み込み処理については、問題1と同様なので、説明を割愛する。
- Mapはインターフェース定義のため、実体を生成する際にはHashMapを使用する。HashMapは、いかなる型のオブジェクトもキーおよび値として格納可能だが、型を明示する事で記述ミスを減らす。
- put()メソッドを使用して、要素を追加する。
- 要素のすべてを取り出す際には、entrySet()メソッドを使用し、キーと値のペアであるEntryを取得する。
- get()メソッドを使用して、指定のキーの要素を取得する。
ここではMapの使い方を確認する問題だ。
まず注目してもらいたいのは、Mapに値を格納した際の順番に関する性質だ。
実際に解答例を実行してみるとわかるが、登録された順番に取得できるとは限らないことに注意してもらいたい。
これは、Mapインターフェースの実装であるHashMapの性質で、あくまでもキーと値のペアを格納する為のオブジェクトであり、その順番は保持されないという事だ。
もし、順序を保持したいのであれば、HashMapの代わりに、LinkedHashMapを使えば良い。使い方もHashMapとほぼ同様なので、解答例のHashMapの部分をLinkedHashMapに代えて実行してみると良いだろう。
問題5 解答/解説
解答例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
public class Main { public static void main(String[] args) { try{ InputStreamReader reader = new InputStreamReader(new FileInputStream(args[0])); BufferedReader buff = new BufferedReader(reader); String text ; ① Map<String,String> map = new TreeMap<String,String>(); while ((text = buff.readLine()) != null) { String[] value = text.split(" "); map.put(value[0], value[1]); } reader.close(); for(Map.Entry<String, String> e : map.entrySet()) { System.out.println(e.getKey() + " : " + e.getValue()); } }catch(FileNotFoundException fnoe){ fnoe.printStackTrace(); }catch(IOException ioe){ ioe.printStackTrace(); } } } |
お気づきかもしれないが、これは問題4の「HashMap」を「TreeMap」に記述を変更しただけで、他の処理に変更は無い。
TreeMapは、Mapインターフェースの実装だが、HashMapやLinkedHashMapとは異なり、キーを一定のルールで並び替えを行って保持する性質を持っている。
この例では、TreeMapの生成時に引数を何も指定していないため、標準の順序(=アルファベット辞書順)となっているが、引数次第で特定の順序を指定する事が出来る。
解答例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class Main { public static void main(String[] args) { try{ InputStreamReader reader = new InputStreamReader(new FileInputStream(args[0])); BufferedReader buff = new BufferedReader(reader); String text ; Map<String,String> map = new TreeMap<String,String>(new NameComparator()); while ((text = buff.readLine()) != null) { String[] value = text.split(" "); map.put(value[0], value[1]); } reader.close(); for(Map.Entry<String, String> e : map.entrySet()) { System.out.println(e.getKey() + " : " + e.getValue()); } }catch(FileNotFoundException fnoe){ fnoe.printStackTrace(); }catch(IOException ioe){ ioe.printStackTrace(); } } } class NameComparator implements Comparator<String>{ @Override public int compare(String o1, String o2) { if(o1.length() > o2.length()){ return 1 ; } if(o1.length() < o2.length()){ return -1 ; } return o1.compareTo(o2); } } |
先ほどの解答とは異なり、TreeMapの生成時にComparatorを指定しており、そのComparatorの実装がNameComparatorだ。
Comparatorは、2つのオブジェクトの順序付けを処理するもので、
- 最初の引数が 2 番目の引数より小さい場合は負の整数
- 両方が等しい場合は 0
- 最初の引数が 2 番目の引数より大きい場合は正の整数
を返せばよい。
TreeMap内部で、順序付けによるソート処理が効率よく行われて保持される。
プログラミングにおける並び替えのアルゴリズムは数多くあるが、それらをJavaで個別に実装する必要は無い。
TreeMapやArraysクラスなど、並び替えを行う為のクラスがすでに用意されており、プログラム作成者はComparatorを定義して、比較ルールを明示するだけで良いのだ。
まとめ
このページでは、Javaの練習問題をまとめてみた。特に知識が問われる問題を中心にまとめている。
ぜひトライしてみて、Javaに対する理解を確認してみていただきたい。
実行例のmain がmanになってますよ
ありがとうございます。修正させていただきます。