個人的備忘録

プログラミングとか勉強した事のまとめ

条件式が複雑になったら場合分けする

IF文のネストは便利ではあるが多用しすぎると可読性の問題に加えて複雑さ故に予期せぬ動きやエラーを誘発しやすい。以下自分の失敗を掲載する。

3つの数の大小 int a; int b; int c; を比較し、最大の数を出力する式において、

if(a > b) {

     if (a < c) {

       System.out.println(c);

       } else if(a>c) {

         System.out.println(a);  

       } else {

           System.out.println(a + c);

         }

(原文どっか行った)

以下

if (a > c) ,if (a == b == c)と3つの場合について記述していたのだが、ごちゃごちゃとした式になるしそっちに気を取られてエラーにも気付かないしで散々だった。大体これだと総当りするせいでどの場合分けをしてどの場合分けをしてないのか書いてる途中でわからなくなる。

 

そこでb-aの変数baを用意し、

if (ba < 0) {

      if (c < a) {

          System.out.println("最大値は" + a);

        } else if(c > a) {

         System.out.println("最大値は" + c);

           } else { System.out.println("最大値はaとc:" + a);

         }

      } if(ba > 0) {

          if(b < c) {

           System.out.println("最大値は" + c);

           } else if(b > c) {

             System.out.println("最大値は" + b);

              } else {

               System.out.println("最大値はbとc:" + b);

              }

           }

if(ba == 0) {

 if(a == c) {

   System.out.println("最大値はaとbとc:" + a);

    } else {

     System.out.println("最大値はaとb:" + a);

    }

}

まぁ不格好ではあると思うがだいぶ見やすくなったし、分ける数も減って動きがわかりやすくなった。 という感じで全部ひとまとまりで表現しようとしないで分解するように心がけたい。

sc.nextIntとsc.nextLineでは末尾の空白を削除する機能が違う

コードの練習をしていたところ、一部のケースでScannerクラスを使った文字列の読み込みにズレが生じる不具合があったので原因を調べたところ、

nextInt()の後にnexiLine()を打つと空白文字を読み込んでしまって上手く行かなかった事が判明した。

配列を読み込んでカンマを足す文を打ち込んでいたのだが、当初は

public class Main {
public static void main(String[] args) {

Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
System.out.print("Hello ");

for (int i =1; i < num; i++) {
String name = sc.nextLine();
System.out.print(name + ",");
}

String lastName = sc.nextLine();
System.out.print(lastName + ".");
}
}

と打っていたところ(最後だけ別に出力してるのは別の文字を付加するため)、最初に空白を打ち出してしまって原因がわからずに悩んでいたのだが、調べてみるとnextInt()には末尾の空白を削除する機能がなく、nextLine()には空白を削除する機能があるというだけの話だということがわかった。

sc.next() とsc.nextLine()の違い あと区切り文字の変更

いまいち理解してなかったので…

next()とnextLine()の違いは「空白も文字列として認識するか否か」で、next()の方は「空白までを1区切りとして認識」、nextLine()の方は「空白は文字列として認識」し、「改行までを1区切りとして認識」するという事。

例えば入力値が"Hello 10"だった場合、

next()では空白を区切りとするので「Hello」が代入されるが、nextLine()では改行までが区切りなので「Hello 10」まで全て代入される。

 

ところでAPIリファレンスを見ていたらuseDelimiterというメソッドがあったので調べたらデリミタ(区切り文字)を変更するものらしい。

文中では

String input = "1 fish 2 fish red fish blue fish";
Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");

と使用することによって「空白+fish+空白」を区切り文字に変更していた。

あまり使用する機会はないかとは思うがあれば便利そうなのでメモしておく。

すべての数字を記録する必要のない大小比較

Paizaの練習問題に「入力の配列による保持」というのがある。

曰く「整数 n と n 個の数 a_1, ..., a_n が改行区切りで与えられます。与えられた a_1, ..., a_n の中で最も大きい数を出力してください。

とのことで、最初に個数nが与えられた後数の羅列が改行区切りで続くのだが、最初これはa_1、\\\ a_nをforで回して配列に格納し、更に入れ子のforの中でMath.maxを使用し配列中の数を一つ一つ大小比較し…といった事を考えながらfor文のスコープに悩まされたりしていたのだが、解答では予め答えを代入するintを0を初期値として用意し、for文の中でsc.nextInt();を使用しつつ、入れ子のif文で答えとなるintとscanner中のintの大小を比較してscanner中のintの方が大きければ答えの方のintをscannerのintで上書きするという単純かつ簡潔な表記法だった。

数が複数あったので何も考えずに配列をどうにか組み込んで…等と考えていたが、問題中では入力された数を全て記憶しておく必要がなく答えとなるintが1つ残っていればいいので理に適った考え方だなと思うと同時にこれくらい自力で気付けるようにしたいなとも思った。

 

なんてことを考えながら以前躓いた「半角スペース区切りでの出力」の問題を解いたらあっさり行けた。

これも勝手にややこしく考えていた問題で、与えられた整数n回分だけ文字列paizaを半角スペース区切りで出力するという問題なのだが、最後のpaizaの後にはスペースを入れてはいけないという文言についてややこしく考えすぎていて、これもやはりfor文で文字列を完成させた後にlengthで文字列の長さを取得した後にStringbuilderでlengthを使って最後の半角スペースを削り出すと言った事を考えながらやって上手く行かなかったのだが、n-1回半角区切りでpaizaと打って最後の1回は別途System.out.print("paiza");と打てば済む話だった。こんな簡単なことではあるが自力で気付けたことでちょっとした達成感があった。

if else文で気を付けるべき事

if構文には、単一の処理を行うif文、条件式の結果によって処理を使い分けるif-else文、そして3つ以上のルートに別れて処理を使い分けられるif-else if-else文があるが、今回はif-else if-else構文で自分がミスしやすい点をまとめた。

まず、構文の構成。

if (条件式①) {

処理①

} else if (条件式②) {

処理②

} else if (条件式③) {

else  {

最終処理

if-else if-else構文では、最初の条件式①に合致すれば処理①を行い、そうでなければ条件式②の判定に以降、そこで合致すれば処理②を行い…と行ったパターンを最後のelse ifブロックまで行う。

ここで大事なのが、最後のelseについてだ。

最後のelseは中身が空(要するに全てfalseなら何も実行しない)の場合はelseごとブロックを省略できるのだが、ここでelseだけ中途半端に残してブロックだけ省くとコンパイルエラーになる。elseの意味を考えてみれば、「もし合致しなければ…」で指示が終わってしまっているので当然だが、「最後は削れる!」とうろ覚えでやってしまいがちなので気をつけたい。

また、これはif-else if-else構文に限ったことではない(ループ文とか)のだが、もしブロック内でしか使わない変数があるなら、スコープの観点からできる限りブロック内で宣言するべきなのにも気を付ける。あわせてif文中の変数が構文を抜けたら使用不可になるのにも気を付ける。 先程と似たような問題だが、変数のスコープに気が行かないのは初学者にありがちな気がするので始めの内は特に気を付けたい。

全くの未経験からどうjavaを勉強するべきか

タイトルの通り、これまでプログラミングに触れたことのない状態の自分がどうjavaを勉強するべきか考え、1ヶ月やってみた結果を書こうと思う。

結論から言うと、教科書の例文レベルの構文を扱うのでやっと、といった所でとても実用に耐えうるものではない(まぁ1ヶ月でマスターできる訳ないので当たり前だが)。

まず、ゴール地点についてだが、これは最低限仕事になるレベル、資格で言えばOracle Certified Java Programmer, Silverレベルを想定している。

その他調べた限りでは基本情報やOracle Master Silverなんかはある程度能力の担保、というか面接でもきちんと資格としてアピールしやすく、且つ未経験からでもなんとか合格への筋道を立てやすいものとして考えられる。が、これは保留にしてまずはJavaに基礎の基礎を理解することから始めている。

ところで、よく「プログラミングにおいては資格なんて何の役にも立たない」という言説を目にする。

もちろんそれはある種の真理ではあるのだろうが、それは職務実績のある場合それをそのままアピールすればいい、という程度の話であって、自分のような手持ちに何もない人間が参入するにはやはりポートフォリオと資格の1つや2つでもないと厳しいだろうと思うし、言語のマスターの指針としても体系だった知識に基づいた資格試験は優秀に感じるので未経験の場合はポートフォリオと資格の二本柱でやっていくのが無難だと思う。

 

さて、使用者の感想をよくみかけるので、スッキリわかるJava入門を教科書に学んでいるのだが、とにかく1つ1つ手探りで進むので進行が遅い。

数学で言えば四則演算にいちいち「なぜ+を使うと数字が増えるの?」とか「加減とと乗除で順番が入れ替わるの?」と言ったバカみたいなレベルの疑問が本当に尽きないので調べるとキリがない。が調べないわけにも行かない。

という訳で非常にノロノロとした進行で1週目を終わらせつつある。

とは言え、後半の章になると、前半で学習した内容が学習の助けになるので最初~中盤のキツイ時期を超えればある程度流れに沿った勉強というのが可能になる。この辺り学校の勉強も同じに感じるので学習というのはやはりある程度パターン化したものだとしみじみする。

つまり、学問に王道なしで、良さげな教本を見つけたら実直にそれらをやっていくしかない、ということに尽きると思う。

 

補足だが、学習に関するwebサービスも手助けになるだろう。

自分はProgateを初歩の学習の補助に使用した。

有名なサービスなのでご存知かとは思うが、一応説明しておくとJavaやJS,HTML&CSSなどのコース別のプログラミング学習を、スライド形式でインプット学習→実際にコードを打ち込んでアウトプット と、実践的にプログラミングを学べるサイトだ。

無料版と有料版があり、自分は無料版しか使用していないが、それでもある程度満足の行く所まで学習できると思う。もちろん他にメインで勉強する媒体があるという前提だが。