プログラミングいちねんせい

プログラミング歴ゼロの初心者がもがくサイトです

コマンドプロンプトからJAVAを実行するのに苦戦しています

コマンドプロンプトからJAVAを実行するのに苦戦しています

JAVAの勉強を始めたときに「コマンドプロンプトではなくIDEを使ったほうが効率がいい」という記事を読んだのでEclipseを使っていました。しかし、先日Twitterでアドバイスをいただきました。

「javac」という言葉は初耳だったのですが実はこれコマンドプロンプトからJAVAを実行するときに使うコマンドだったんです。そして調べてみるとJAVAコマンドプロンプトから実行させて仕組みを知ることが大切ということを知りました。その大切な部分をEclipseに任せていたばかりに簡単なHello Worldさえも実行できないトラブルに遭ったのでシェアします。

最大の敵の環境変数

私はWindows7JAVAの勉強をしています。そして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 -versionjdkのバージョンを調べると1.8.0_131でした。java -version1.8.0_131です。これはJREJDKのそれぞれのバージョンを表示しているらしいです。

調べた結果「環境変数」「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よりも優先して使用することをお薦めします。

今のところは文字列の連結は+演算子StringBuilderStringBufferの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つ目のコードの変数sbfor文の条件がtrueであれば、その都度newされるので変数sbの中身がnullになります。気をつけましょう。

メソッドを試す

appendメソッドで文字列を末尾にできます。これは簡単ですね。

insertメソッドです。引数で指定した箇所に文字列を挿入します。

deleteCharAtメソッドです。引数で指定した箇所の文字列を削除します。

便利なメソッドばかりなので文字列を扱うときはStringBuilderは便利ですね。

用語

  • シーケンス
    • 連続、順序
  • API
    • システムやプログラムに用意された拡張機能
  • バッファ
    • データを一時的に記憶する場所
  • スレッド
    • 処理をするCPUの単位

あとがき

簡単なプログラムのときはStringで書くと思いますがStringBuilderには慣れておきたいです。

初心者殺しのfor文のネストを解説します

みなさんはfor文と仲良くやっていますか?私は昨日まで喧嘩ばかりしていました。あっちに行ったりこっちに行ったりと縦横無尽に駆け回るfor文がなにを考えているのかわかりませんでした。しかし、ふと目に止まったJAVAの質問の解を自分の手でやってみようと試行錯誤していたときに一筋の光が差し込みfor文がこう言いました。

「友達になろう」と。

for文の基本

まずはfor文の基本をおさらいしましょう。for文は初期化、条件、変化、実行内容の4つで構成されています。

基本

  • 初期化
    • 変数の値を決める場所です。プログラミング初心者は初期化と聞くと0になると考えがちですが間違いです。実際はどんな値で開始するかという意味です。for文が開始されると最初に一度だけ実行されます。変数の型を宣言するのを忘れないでください
  • 条件
    • この条件がfalseになると終了します。つまり条件が満たされている限り実行内容が繰り返されます
  • 変化
    • 条件に書いた変数がどう変化するのかを指定します
  • 実行内容
    • 計算したり文字を出力したりといった内容を書きます

実演

  • int
    • int型を宣言しています
  • i = 0
    • 変数i0を代入します
  • i < 10
    • i10未満ならtrueです。つまりi9までのあいだは実行内容を繰り返します
  • i++
    • iが1つ増えます
  • System.out.println("Hello!")
    • Hello!という文字を出力します

動き

実演をもとに見ていきましょう。for文が開始されると最初に動くのは初期化です。変数iの値は0ですね。for文はi0だと確認してから条件に移ります。条件は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文は終了です。お疲れ様でした。

流れをリスト化すると以下になります。

  1. for文開始
  2. 初期化
  3. 条件
  4. 実行内容
  5. 変化
  6. 条件(以下略)
  7. 条件がfalseならfor文終了

実は簡単だったfor文のネスト

for文の基本をおさえたところで次はネストです。私はfor文のネストをなんとなくわかったつもりになっていましたが実際に書いてみると上のfor文と下のforがどういう風に絡むのかという点がわかっていませんでした。

では、九九の計算プログラムを紐解きながらネストの動きを見ていきましょう。

九九を表示するプログラム

ここから先は「上のfor文」ではなく「外側のfor文」、「下のfor文」ではなく「内側のfor文」という表現になります。では、3行目からです。int x = 1;から実行されます。次にx < 10;です。今回はtrueなので実行内容に移ります。初心者は実行内容がどこなのか真っ白になるところですが下の図をご覧ください。

f:id:javacurry:20170620195251p:plain

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++y10となり条件に移ります。10 < 10falseなので内側のfor文(青)の一番下のSystem.out.println()が実行されて改行されます。これで内側のfor文(青)は終了するので外側のfor文(赤)に戻ります。ここからは繰り返しです。2 * 1から始まり2 * 9までいけば改行で3 * 1が実行されます。では実際の実行結果を見てみましょう。

これがfor文のネストを利用した九九のプログラムの動きです。紐解くと簡単ですね。これを応用して冒頭ではなしたとある質問を作ってみました。その結果がこちらです。

これはなにをやっているかというとfor文を使っての数を1行ごとに増やして三角形を表現したんです。1つずつ増える形と1つずつ減る形を作り上下を合わせたものを表示しました。以下がそのプログラムです。

ここまで読んだみなさんなら、もう解説しなくとも紐解けますね。

あとがき

プログラミング初心者にとってfor文のネストの動きをすぐに理解するのは難しいです。見るだけではなく、まずは自分の手で試行錯誤するのをおすすめします。今回作った三角形を左側に反転させたものを作りたくなり四角形に挑戦したのですが半角の空白を連続で表示することができずに断念しました。いつかfor文で簡単な絵を描いてみたいです。