コマンドプロンプトからJAVAを実行するのに苦戦しています
JAVAの勉強を始めたときに「コマンドプロンプトではなくIDEを使ったほうが効率がいい」という記事を読んだのでEclipseを使っていました。しかし、先日Twitterでアドバイスをいただきました。
javapしたり速度実測したりするともっと良い記事になると思うよ :-) https://t.co/NvHI63pK8x
— なぎせ ゆうき (@nagise) 2017年6月22日
「javac」という言葉は初耳だったのですが実はこれコマンドプロンプトからJAVAを実行するときに使うコマンドだったんです。そして調べてみるとJAVAはコマンドプロンプトから実行させて仕組みを知ることが大切ということを知りました。その大切な部分をEclipseに任せていたばかりに簡単なHello World
さえも実行できないトラブルに遭ったのでシェアします。
最大の敵の環境変数
私はWindows7でJAVAの勉強をしています。そしてWindowsにはコマンドプロンプトというCUIが用意されています。起動方法はスタートボタンからアクセサリを選ぶかスタートボタンを押したときに表示される「プログラムとファイルの検索」のなかでcmd
と入力すれば表示されます。
起動したら目的であるJAVAの実行ファイルがある場所へと移動します。私はFドライブのProgramming\JAVA\study\src\test
フォルダにMain.javaを保存してあるのでf:
と入力してFドライブに移動したあと目的のフォルダを指定します。cd programming\java\study\src\test
と入力すると無事に移動できました。ここでjavac ファイル名.java
でコンパイルできます。
javac Main.java
と入力すると何も起きることなく、さきほどのフォルダ名が表示されました。これでコンパイルは成功です。ここでエラーがあればエラー内容が表示されます。コンパイルが成功したら拡張子を入力せずにjava ファイル名
で実行でるはずなのですがゴール手前で頭を抱える事態になりました。
java Main
と入力すると「エラー: メイン・クラスtest.Mainが見つからなかったかロードできませんでした」と表示されます。パッケージ名も入力したほうがいいという情報を見てjava test.Main
と入力しましたが全く同じエラーが返ってきます。javac
と入力するとjavac
のオプションが表示されるのでjavac
は動いているようです。javac -version
でjdkのバージョンを調べると1.8.0_131
でした。java -version
も1.8.0_131
です。これはJREとJDKのそれぞれのバージョンを表示しているらしいです。
調べた結果「環境変数」「Path」「JAVA_HOME」「クラスパス」が鍵になるようですが環境変数からPathの値を;
で区切り指定しても同じエラーに終始してしまい、検索した記事の解決策は全て試した状況なので今のところ打つ手がなく途方にくれています。気になるのはJDK
が2種類あり古い方を参照しているようなのですが環境変数を全てチェックしても、古いJDK
へのパスは見当たらないのでどうやって参照しているのかわかっていません。古いJDK
を削除すると「JDK
が見当たりません」とエラーが出るのでこれが疑わしいです。
使用PCが古く把握できていないことも多いので、この機会にWindowsを再インストールして環境をリセットするというのも、ひとつの手かもしれません。上手く解決できれば同じ原因で悩む方のヒントになったかもしれませんが今回は負け試合ということで終了です。
用語
- IDE
- CUI
- Character-based User Interfaceの略でキーボードからの入力のみでソフトウェアを操作する仕組みです
- JRE
- JAVAを動かすための環境ファイルです
- JDK
- JAVAの開発環境ファイルです
- クラスパス
- JAVAが実行されるときにファイルの検索を効率的にするために指定するパスです
- 環境変数
- OSがアプリケーションに変数を渡すことができる機能
あとがき
問題は解決していませんがコマンドプロンプトでいろいろ入力するのは楽しいです。
文字列を連結するなら演算子ではなくStringBuilderが推奨されるらしいです
文字の連結といえば+
演算子を使ったおなじみの式でしたが、それよりもStringBuilder
が推奨されているという噂を聞きつけました。というわけで今回もいろいろ見ていきます。
StringBuilderとは
文字の可変シーケンスです。このクラスは、StringBufferと互換性があるAPIを提供しますが、同期化は保証されません。このクラスは、文字列バッファが単一のスレッド(一般的なケース)により使用されていた場合のStringBufferの簡単な代替として使用されるよう設計されています。このクラスは、ほとんどの実装で高速に実行されるので、可能な場合は、StringBufferよりも優先して使用することをお薦めします。
今のところは文字列の連結は+
演算子、StringBuilder
、StringBuffer
の3つがありStringBuffer
よりStringBuilder
のほうが処理速度が速いので優先して使ったほうがいいみたいですね。
StringBuilderの基本的なオペレーションには、appendメソッドおよびinsertメソッドがあり、これらのメソッドはどんな種類のデータも受け取ることができるようにオーバーロードされています。メソッドはそれぞれ与えられたデータを効率的に文字列に変換し、文字列中の文字を文字列ビルダーに追加または挿入します。appendメソッドは常に、ビルダーの末尾に与えられた文字を追加し、insertメソッドは指定された位置に文字を追加します。
たとえば、zを、現在「start」を含む文字列ビルダー・オブジェクトと見なす場合、z.append("le")は文字列ビルダーの内容が「startle」になるように変更するのに対して、z.insert(4, "le")というメソッド呼出しは文字列ビルダーの内容が「starlet」になるように作用します。
一般に、sbがStringBuilderのインスタンスを参照している場合、sb.append(x)はsb.insert(sb.length(), x)と同じ結果になります。
append
メソッドとinsert
メソッドが代表メソッドでappend
メソッドが末尾に文字列を追加しinsert
メソッドが引数で指定した位置に文字列を追加するみたいです。
プラス演算子との違い
可変であるStringBuilder
に対して固定であるString
は文字列を追加するたびにnew
されるらしいです。
この場合3回もnew
されるのでその分のメモリを消費します。それが原因で+
演算子での文字列結合は遅いみたいです。そう言われるとStringBuilder
を使わない手はないですね。
ここで初心者が一瞬混乱する例を見てみましょう。
この結果はどうなると思いますか?■■■■■■■■■■
が出力されると思いきや実は■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
こう表示されるんです。■
が55個並んでいます。いったいどういうことでしょうか?原因は3行目のStringBuilder sb = new StringBuilder();
です。for
文の外側でsb
変数を定義しているのでfor
文の実行内容が変数sb
の末尾に追加されていくわけです。ではfor
文の中に入れてみましょう。
これで結果は■■■■■■■■■■
となります。考えてみればなんでもないのですが2つ目のコードの変数sb
はfor
文の条件がtrue
であれば、その都度new
されるので変数sb
の中身がnull
になります。気をつけましょう。
メソッドを試す
append
メソッドで文字列を末尾にできます。これは簡単ですね。
insert
メソッドです。引数で指定した箇所に文字列を挿入します。
deleteCharAt
メソッドです。引数で指定した箇所の文字列を削除します。
便利なメソッドばかりなので文字列を扱うときはStringBuilder
は便利ですね。
用語
あとがき
簡単なプログラムのときはString
で書くと思いますがStringBuilder
には慣れておきたいです。
初心者殺しのfor文のネストを解説します
みなさんはfor
文と仲良くやっていますか?私は昨日まで喧嘩ばかりしていました。あっちに行ったりこっちに行ったりと縦横無尽に駆け回るfor
文がなにを考えているのかわかりませんでした。しかし、ふと目に止まったJAVAの質問の解を自分の手でやってみようと試行錯誤していたときに一筋の光が差し込みfor
文がこう言いました。
「友達になろう」と。
for文の基本
まずはfor
文の基本をおさらいしましょう。for
文は初期化、条件、変化、実行内容の4つで構成されています。
基本
- 初期化
- 変数の値を決める場所です。プログラミング初心者は初期化と聞くと0になると考えがちですが間違いです。実際はどんな値で開始するかという意味です。
for
文が開始されると最初に一度だけ実行されます。変数の型を宣言するのを忘れないでください
- 変数の値を決める場所です。プログラミング初心者は初期化と聞くと0になると考えがちですが間違いです。実際はどんな値で開始するかという意味です。
- 条件
- この条件が
false
になると終了します。つまり条件が満たされている限り実行内容が繰り返されます
- この条件が
- 変化
- 条件に書いた変数がどう変化するのかを指定します
- 実行内容
- 計算したり文字を出力したりといった内容を書きます
実演
int
int
型を宣言しています
i = 0
- 変数
i
に0
を代入します
- 変数
i < 10
i
が10
未満ならtrue
です。つまりi
が9
までのあいだは実行内容を繰り返します
i++
i
が1つ増えます
System.out.println("Hello!")
Hello!
という文字を出力します
動き
実演をもとに見ていきましょう。for
文が開始されると最初に動くのは初期化です。変数i
の値は0
ですね。for
文はi
は0
だと確認してから条件に移ります。条件はi < 10
です。今の時点では0 < 10
と同じです。日本語に直すと「0は10より小さい」と言えるので条件はtrue
ですね。条件がtrue
ということが確認できたので実行内容の部分が動きます。
System.out.println("Hello!")
が実行されると次は変化に移ります。変化はi++
です。今の時点では0++
なので1
になりました。この1
は実行の変数に代入するために条件に移ります。今の時点では1 < 10
です。true
ですね。というわけでまた実行内容に移ります。
この流れが何度も続くと条件のなかが10 < 10
になります。これはtrue
でしょうか?false
でしょうか?false
ですね。これでfor
文は終了です。お疲れ様でした。
流れをリスト化すると以下になります。
for
文開始- 初期化
- 条件
- 実行内容
- 変化
- 条件(以下略)
- 条件が
false
ならfor
文終了
実は簡単だったfor文のネスト
for
文の基本をおさえたところで次はネストです。私はfor
文のネストをなんとなくわかったつもりになっていましたが実際に書いてみると上のfor
文と下のfor
がどういう風に絡むのかという点がわかっていませんでした。
では、九九の計算プログラムを紐解きながらネストの動きを見ていきましょう。
九九を表示するプログラム
ここから先は「上のfor
文」ではなく「外側のfor
文」、「下のfor
文」ではなく「内側のfor
文」という表現になります。では、3行目からです。int x = 1;
から実行されます。次にx < 10;
です。今回はtrue
なので実行内容に移ります。初心者は実行内容がどこなのか真っ白になるところですが下の図をご覧ください。
for
文を拡大して色分けしました。これを見るとわかるように外側のfor
文の実行内容というのは内側である青のfor
文なんです。内側のfor
文(青)の初期値のint y = 1
が実行されて条件に移ります。y < 10;
なので代入して1 < 10
です。true
なので実行内容に移ります。System.out.print(x * y)
です。x
は外側のfor
文の変数でしたね。今の時点ではx=1
です。なので、ここは1 * 1
が実行されて結果は1
です。画面に1
が表示されて次の行に移ります。System.out.print(" ")
は半角の空白が表示されます。
ここまで実行されたら次は変化に移ります。y++
なのでy
が1つ増えて2
と変化して次は条件に移ります。y < 10
なので2 < 10
となりtrue
なので、また実行内容へと移ります。System.out.print(x * y)
です。1 * 2
なので結果は2
となり画面へ表示され次の行の半角の空白も表示されて、また変化に移り以降は繰り返しです。このような動きでy
の値が9
までいくと画面には1 2 3 4 5 6 7 8 9
と表示されますね。このあとなにが起きるかを見てみましょう。
y++
でy
が10
となり条件に移ります。10 < 10
はfalse
なので内側のfor
文(青)の一番下のSystem.out.println()
が実行されて改行されます。これで内側のfor
文(青)は終了するので外側のfor
文(赤)に戻ります。ここからは繰り返しです。2 * 1
から始まり2 * 9
までいけば改行で3 * 1
が実行されます。では実際の実行結果を見てみましょう。
これがfor
文のネストを利用した九九のプログラムの動きです。紐解くと簡単ですね。これを応用して冒頭ではなしたとある質問を作ってみました。その結果がこちらです。
これはなにをやっているかというとfor
文を使って■
の数を1行ごとに増やして三角形を表現したんです。1つずつ増える形と1つずつ減る形を作り上下を合わせたものを表示しました。以下がそのプログラムです。
ここまで読んだみなさんなら、もう解説しなくとも紐解けますね。
あとがき
プログラミング初心者にとってfor
文のネストの動きをすぐに理解するのは難しいです。見るだけではなく、まずは自分の手で試行錯誤するのをおすすめします。今回作った三角形を左側に反転させたものを作りたくなり四角形に挑戦したのですが半角の空白を連続で表示することができずに断念しました。いつかfor
文で簡単な絵を描いてみたいです。