勉強メモ@プロJava/その11
第13章 処理の難しさの段階
13.2.1 状態遷移の管理とenum
例題
文字列が小数点付きの数値の表示として妥当かどうか判定するプログラムを考えてみましょう。
src/main/java/projava/CheckFloat.java
package projava; public class CheckFloat { enum FloatState { START, INT, FRAC_START, FRAC, ZERO } static boolean check(String data){ var state = FloatState.START; for (char ch : data.toCharArray()){ switch (state){ case START -> {//開始 if (ch == '0'){ state = FloatState.ZERO; }else if(ch >= '1' && ch <= '9'){ state = FloatState.INT; }else{ return false; } } case ZERO -> {//頭のゼロ if (ch == '.'){ state = FloatState.FRAC_START; }else{ return false; } } case INT -> {//整数部 if (ch >= '0' && ch <= '9'){ state = FloatState.INT; }else if(ch == '.'){ state = FloatState.FRAC_START; }else{ return false; } } case FRAC_START, FRAC -> {//小数部 if(ch >= '0' && ch <= '9'){ state = FloatState.FRAC; }else{ return false; } } } } return switch (state){ case ZERO, INT, FRAC -> true; default -> false; }; } public static void main(String[] args) { System.out.println(check("")); System.out.println(check("012")); System.out.println(check(".12")); System.out.println(check("12.")); System.out.println(check("1.2.3")); System.out.println(check("1..3")); System.out.println(check("0")); System.out.println(check("12")); System.out.println(check("12.3")); System.out.println(check("0.3")); System.out.println(check("12.30")); } }
▼コンソール
おおー!!!
練習問題(上記例題の続き)
1.小数部の最後が0で終わると不適になるように判定を変更してみましょう。「12.30」や「12.0」は不適です。
2.先頭に負の符号を表すを付けることができるように判定を変更してみましょう。「123」はOKですが「123」や「123」は不適です。
src/main/java/projava/ExCheckFloat.java
package projava; public class ExCheckFloat { enum FloatState { //「小数の末尾」「負の数」の状態を追加 START, INT, FRAC_START, FRAC, ZERO, FRAC_END, NEGATIVE } static boolean check(String data){ var state = FloatState.START; //文字カウンタを宣言 int count = 0; for (char ch : data.toCharArray()){ count++; switch (state){ case START -> {//開始 if (ch == '0'){ state = FloatState.ZERO; }else if(ch >= '1' && ch <= '9') { state = FloatState.INT; }else if (ch == '-'){ state = FloatState.NEGATIVE; }else{ return false; } } case NEGATIVE -> {//stateがNEGATIVE、負の数の場合 if (ch >= '1' && ch <= '9'){ state = FloatState.INT; }else{ return false; } } case ZERO -> {//頭のゼロ if (ch == '.'){ state = FloatState.FRAC_START; }else{ return false; } } case INT -> {//整数部 if (ch >= '0' && ch <= '9'){ state = FloatState.INT; }else if(ch == '.'){ state = FloatState.FRAC_START; }else{ return false; } } case FRAC_START, FRAC -> {//小数部 if (count == data.toCharArray().length){ if (ch >= '1' && ch <= '9'){ state = FloatState.FRAC_END; }else { return false; } }else{ if(ch >= '0' && ch <= '9'){ state = FloatState.FRAC; }else{ return false; } } } } } return switch (state){ case ZERO, INT, FRAC_END -> true; default -> false; }; } public static void main(String[] args) { /*System.out.println(check("")); System.out.println(check("012")); System.out.println(check(".12")); System.out.println(check("12.")); System.out.println(check("1.2.3")); System.out.println(check("1..3")); System.out.println(check("0")); System.out.println(check("12")); System.out.println(check("12.3")); System.out.println(check("0.3")); System.out.println(check("12.30"));*/ //追加ケース System.out.println("練習問題1のチェック"); System.out.print("12.30はfalseでしょ?:"); System.out.println(check("12.30")); System.out.print("12.0はfalseでしょ?:"); System.out.println(check("12.0")); System.out.print("0.0はfalseでしょ?:"); System.out.println(check("0.0")); System.out.println(""); System.out.println("練習問題2のチェック"); System.out.print("-123はtrueでしょ?:"); System.out.println(check("-123")); System.out.print("--123はfalseでしょ?:"); System.out.println(check("--123")); System.out.print("-12-3はfalseでしょ?:"); System.out.println(check("-12-3")); System.out.print("-1.0はfalseでしょ?:"); System.out.println(check("-1.0")); } }
▼コンソール
ひとまずいけたと思われる!
しかーし、stateがFRAC_STARTまたはFRACの時のifネストが深すぎ??うーむ。
答え合わせ!
練習問題1について。
その時アクティブな要素がゼロならステータスをFRAC_STARTにすればよかったのか!!
そしたらカウンタ用意する必要もなかったのだ〜〜なるほど!!
練習問題2について。
「−」符号の後ろに「0」がくるのはNGという前提で書いたけど、その場合はステータスをZEROにすれば良いのか。
うおおおお。ちょっと待って混乱してきた。あかん…明日解説ブログ読み直す😂
勉強メモ@プロJava/その10
第13章 処理の難しさの段階
13.1.2 隠れた状態を扱うループ
練習問題
1.受け取った文字列のアルファベットを、最初は小文字で出力し、0を受け取ったら次からのアルファベットは大文字に、1を受け取ったら次からのアルファベットを小文字で出力してみましょう。
例:aa0bcd1efg1gg0abc➡aaBCDefgggABC
2.文字列を受け取って、数字以外はそのまま出力し、数字が来たら直前の文字をその数字に1を足した文字数分出力してください。
例:ab0c1ba2bc9cd1➡abbcccbaaaabccccccccccccddd
src/main/java/projava/LoopExercise2.java
package projava; public class LoopExercise2 { public static void main(String[] args) { System.out.println("--練習問題1:受け取った文字列のアルファベットを、最初は小文字で出力し、" + "\n" + "\t" + "0を受け取ったら次からのアルファベットは大文字に、" + "\n" + "\t" + "1を受け取ったら次からのアルファベットを小文字で出力--"); caseSwitch("aa0bcd1efg1gg0abc"); System.out.println(""); System.out.println("--練習問題2:文字列を受け取って、数字以外はそのまま出力し、" + "\n" + "\t" + "数字が来たら直前の文字をその数字に1を足した文字数分出力--"); expandPressedData("ab0c1ba2bc9cd1"); } //練習問題1 初め小文字、0きたら以降大文字、1きたら以降小文字 public static void caseSwitch(String data){ boolean isBigCase = false; var builder = new StringBuilder(); for(char ch : data.toCharArray()){ if (ch == '0' || ch == '1'){ isBigCase = ch == '0' ? true : false; continue; } if(isBigCase){ ch = Character.toUpperCase(ch); } builder.append(ch); } var result = builder.toString(); System.out.println(data); System.out.println(result); } //練習問題2 圧縮された文字列を展開 public static void expandPressedData(String data){ var builder = new StringBuilder(); char prev = 0; for (char ch : data.toCharArray()){ if(Character.isDigit(ch)){ String s = String.valueOf(prev).repeat(Character.getNumericValue(ch) + 1); builder.append(s); prev = 0; }else{ builder.append(ch); prev = ch; } } var result = builder.toString(); System.out.println(data); System.out.println(result); } }
▼コンソール
うむ!ひとまず「こうなってほしい」ができたはず!
昨日よりちょっとだけコードの組み立てが速くできた気がする( ^ω^ )ただの願望か?笑
ぬ〜ただやっぱもっときれいに滑らかに書けるようになりたいのお〜!!!
勉強メモ@プロJava/その9
第13章 処理の難しさの段階
13.1.1 他のデータを参照するループ
練習問題
1.奇数番目の文字を、続く偶数番目の文字と入れ替えて出力するようにしてみましょう。続く文字がない場合はそのまま出力します。例えば"abcde"に対して"badce"と出力します。
2.1つ後の要素と比べて大きいほうを格納した配列を作ってみましょう。最後の要素は最後にそのまま出力されます。例えば、{3,6,9,4,2,1,5}に対して{6,9,9,4,2,5,5}が生成されます。
src/main/java/projava/LoopExercise.java
package projava; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class LoopExercise { public static void main(String[] args) { System.out.println("--練習問題1:文字列「abcde」について、" + "\n" + "\t" + "奇数番目の文字を、続く偶数盤目の文字と入れ替えて出力--"); invertPrevNext("abcde"); System.out.println("--練習問題2:一つ後の要素と比べて大きい方を格納した配列を作る" + "\n" + "\t" + "※等しい場合はその要素を格納--"); System.out.println("配列{3, 6, 9, 4, 2, 1, 5}を実引数とすると…"); makeBiggerNumbersArray(new int[]{3, 6, 9, 4, 2, 1, 5}); } //練習問題1 public static void invertPrevNext(String data){ StringBuilder builder = new StringBuilder(); char ch, odd = 0; for (int i = 0; i < data.length(); i++) { ch = data.charAt(i); if(i % 2 == 0 && i != data.length()-1){ odd = ch; continue; } builder.append(ch); if(odd != 0){ builder.append(odd); } odd = 0; } System.out.println(builder); } //練習問題2 public static void makeBiggerNumbersArray(int[] data){ List<Integer> list = new ArrayList<>(); for (int i = 0; i < data.length; i++) { if(i == data.length-1){ list.add(data[i]); break; } int bigger = data[i] >= data[i + 1] ? data[i] : data[i + 1]; list.add(bigger); } System.out.println(Arrays.toString(list.toArray())); } }
▼コンソール
おっけい!結構時間かかっちゃった^^;
でももっとスッキリ書けるんじゃないかな…まあテキスト2周目以降の課題とするか。
頭も鍛えれば鍛えられるはず…と今後の自分に期待じゃー(`_´)ゞ
勉強メモ@プロJava/その8
Webの裏側を見てみる
HTTPリクエスト p.251
HTTPのバージョンについて、下記のこと。
バージョンには1.0か1.1を指定できますが、通常は1.1を使用します。
なんで「通常は1.1なん?1.0とどう違うの?」と思ってググったら、下記のこと。そうなんやφ(・・
「HTTP 1.0」と「HTTP 1.1」の大きな違いは、keep-alive(キープアライブ)機能にあります。 keep-aliveは、通信を一定期間保った状態とする機能で、画像を含む多く含むページの表示などが速くなる効果があります。 現在のホームページは、ほぼ全てで画像など多くの情報が含まれていますので、「HTTP 1.1」の利用が主流となっています。
参考サイト: www.cman.jp
まずはよくわからんでも書ーーく!!
src/main/java/projava/WebClient.java
package projava; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class WebClient { public static void main(String[] args) throws IOException { var domain = "example.com"; try (var soc = new Socket(domain,80); var pw = new PrintWriter(soc.getOutputStream()); var isr = new InputStreamReader(soc.getInputStream()); var bur = new BufferedReader(isr)) { pw.println("GET /index.html HTTP/1.1"); pw.println("Host: " + domain); pw.println(); pw.flush(); bur.lines() .limit(18) .forEach(System.out :: println); } } }
▼コンソール
おお!リクエストとレスポンスのラリーができたんだよね!?
ちなみにこの章の内容とは関係ないけどフォントサイズ小さくしたかったので「⌘」+「,」で設定画面を表示して変更。
pleiades.io
HttpClient API
src/main/java/projava/WebClient2.java
package projava; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class WebClient2 { public static void main(String[] args) throws IOException, InterruptedException { HttpClient client = HttpClient.newHttpClient(); URI uri = URI.create("https://example.com/"); HttpRequest req = HttpRequest.newBuilder(uri).build(); HttpResponse<String> response = client.send(req,HttpResponse.BodyHandlers.ofString()); String body = response.body(); body.lines() .limit(5) .forEach(System.out::println); } }
▼コンソール
うーむ、ふむふむ。。。「こう書いたらこうなるのか〜」という感じでまだふわっとしか理解できない。。
が!テキスト1周目なのでとりあえず先へ!!
Webサーバーを作る p.259
src/main/java/projava/WebServer.java
package projava; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class WebServer { public static void main(String[] args) throws IOException { var server = new ServerSocket(8880); for (;;){ try (Socket soc = server.accept(); var isr = new InputStreamReader(soc.getInputStream()); var bur = new BufferedReader(isr); var w = new PrintWriter(soc.getOutputStream()) ) { System.out.println("connected from " + soc.getInetAddress()); bur.lines() .takeWhile(line -> !line.isEmpty()) .forEach(System.out::println); w.println(""" HTTP/1.1 200 OK Content-Type: text/html <html><head><title>Hello</title></head> <body><h1>Hello</h1>It works!</body></html> """); } } } }
実行しても、確かに何も表示されない。
▼コンソール
だがブラウザから http://localhost:8880 にアクセスすると…
おお!いっとわーくす!で、コンソールに戻ると、さっきは何も表示されていなかったのに、
だーっとリクエストヘッダーが!
MIMEタイプの変更 p.262
Content-Typeをtext/htmlからtext/plainに変更
で、先ほど同様ブラウザから http://localhost:8880 にアクセスすると…
文字列そのままに表示に。おもしろ( ^ω^ )
ちなみに「plain」は「簡単な」とか「はっきり見える」といった意味なのだね〜
plain とは 意味・読み方・表現 | Weblio英和辞書
これにて第12章は終了!正直仕組みはまだ理解できてないけど「こういうこともできるんだな〜」と(☻-☻)
この次の第13章「処理の難しさの段階」から、文字通りでますます難しくなりそうだぜっ
うほっ
勉強メモ@プロJava/その7
再帰とスタック & 第12章 入出力と例外
再帰 練習問題p.228
次のforループでの処理を再帰に書き換えてみましょう。
「プロになるJava」より
gihyo.jp
for(inti=3;i>0;i){ System.out.println(i); }
public class RecursionExercise { static void loop(int i){ if (i == 0){ return; } System.out.println(i); i--; loop(i); }
▼コンソール
うむ!ここからは先は【第12章 入出力と例外】に突入や!
疑問メモ
少し調べてわからなければ後で調べることにして先に進む、1周目だから^^;
1.ポート番号は65535までの数字が使えるとのことだが、この数字なに?(p.243)
⇨16bit、つまり2バイトまで使えるということ。1023まで用途決まっているということだがこれは10bitまでは定員が埋まっているということ。
しかし1023も何に使われているのか?
⇨いくつか関連サイトを閲覧したが、こちらを読む読む
⇨どうして「未割り当て」とか「非公式」とかあるんや?てかなんで10bit分を「予約枠」にした?キリよく1バイトにすれば良かったんじゃ?
これどういう順番で割り当ててる??
⇨学習優先度としてはまずこの「プロJava」を進めたい。沼にはまりそうなので、もう今は気にせず進める…
try-with-resources メモ
IntelliJ IDEA上で、例外が途中で発生しようが必ずcloseする必要があるものを作り出している箇所にカーソルを当てて「option + return」すると、
「try-with-resourcesで囲む」という選択肢が出てくる!
囲んでくれた!↓
try (Socket soc = server.accept()) { System.out.println("connect from " + soc.getInetAddress()); InputStream input = soc.getInputStream(); System.out.println(input.read()); input.close(); soc.close(); }
「必ず閉じなければいけない」のは入力ストリームも同じなので、追加。
try (Socket soc = server.accept(); InputStream input = soc.getInputStream()) { System.out.println("connect from " + soc.getInetAddress()); System.out.println(input.read()); input.close(); soc.close(); }
うむ!
練習問題p.248
SimpleServerを起動せずにSimpleClientを実行すると例外java.net.ConnectExceptionが発生します。例外処理をして「サーバーが起動していません」とメッセージを出すようにしてみましょう。
▼SimpleServer.java
package projava; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class SimpleServer { public static void main(String[] args) throws IOException { var server = new ServerSocket(1600); System.out.println("Waiting..."); try (Socket soc = server.accept(); InputStream input = soc.getInputStream()) { System.out.println("connect from " + soc.getInetAddress()); System.out.println(input.read()); } } }
▼SimpleClient.java(書き換え前)
package projava; import java.io.IOException; import java.io.OutputStream; import java.net.ConnectException; import java.net.Socket; public class SimpleClient { public static void main(String[] args) throws IOException { try (var soc = new Socket("localhost", 1600); OutputStream output = soc.getOutputStream()) { output.write(234); } } }
▼コンソール
▼SimpleClient.java(書き換え後)
package projava; import java.io.IOException; import java.io.OutputStream; import java.net.ConnectException; import java.net.Socket; public class SimpleClient { public static void main(String[] args) throws IOException { try (var soc = new Socket("localhost", 1600); OutputStream output = soc.getOutputStream()) { output.write(234); } catch (ConnectException e){ e.printStackTrace(); System.out.println("サーバーが起動していません"); } } }
▼コンソール
うむ!!
ちなみに、macOSで「option + command + /」で、複数行まとめてコメントアウト&解除できるとな✨
ちょっとずつでも、これからも進めてこ〜
これから数日間は大自然と交流タームなので笑、またその後に更新する_φ( ̄ー ̄ )
勉強メモ@プロJava/その6
第11章メソッド
▼個人的に忘れがちなのでマークした箇所
staticメソッドから呼び出す同じクラス内のメソッドはstaticメソッドにする必要がある
項番11.1.3練習問題p.216
「(名前)さんの平均点は(平均)点です」と表示するshowResultメソッドをStudentレコードに用意してみましょう。
recordにまだ慣れてないからちょっと違和感…配列とクラスのあいのこ?
package projava; public class InstanceMethodExercise { record Student(String name,int englishScore,int mathScore){ int average(){ return (this.englishScore() + this.mathScore()) /2; } void showResult(){ System.out.println("%sさんの平均点は%d点です".formatted(this.name(),this.average())); } } public static void main(String[] args) { var kis = new Student("kis",60,80); kis.showResult(); } }
▼コンソール
うむ!
練習問題 about ラムダ式p.219
1.次のメソッドをラムダ式で表してみましょう。
boolean check(String s){ return s.contains("y"); }
s -> s.contains("y")
2.次のメソッドをラムダ式で表してみましょう。
void print(String s){
System.out.println(s);
}
s -> System.out.println(s);
3.次のラムダ式をupperという名前のメソッドにしてみましょう。引数と戻り値の型はどちらもStringです。
s -> s.toUpperCase()
String upper(String s){
return s.toUpperCase();
}
4.次のラムダ式をemptyという名前のメソッドにしてみましょう。引数の型はString、戻り値の型はbooleanです。
s -> s.isEmpty()
boolean empty(String s){ return s.isEmpty(); }
練習問題 about メソッド参照p.222
1.次のコードをメソッド参照を使って書き換えてみましょう。
IntStream.of(nums).mapToObj(n ->"*".repeat(n)).toList()
IntStream.of(nums).mapToObj("*" :: repeat).toList()
練習問題(ラムダ式からメソッド参照への書き換え)p.223
1.次のラムダ式をメソッド参照を使って書き換えてみましょう。
names.stream().map(s ->s.toUpperCase()).toList()
names.stream().map(String :: toUpperCase).toList()
2.次のラムダ式をメソッド参照を使って書き換えてみましょう。
names.stream().map(s ->"%sさん".formatted(s)).toList()
names.stream().map("%sさん" :: formatted).toList()
3.メソッド参照をラムダ式を使って書き換えてみましょう。
names.stream().map(String::toLowerCase).toList()
names.stream().map(s -> s.toLowerCase()).toList()
そして答え合わせ_φ( ̄ー ̄ )
おっいけてるのでは…!わふーい!
メソッド参照の書き方はまだ慣れないけど、引数の妥当性を考慮する手間が省けてスッキリ書けていいな。
明日も「あさJava」できるようにがんばろっと^^
勉強メモ@プロJava/その5
第11章メソッド
▼読者ファーストで書いてくださった書籍だと再認識した
メソッドが結果として返す値を戻り値や返り値と言います。ただ、「返り値」は口頭で使うと殺伐とした感じがあるのと、そういった殺伐とした感じに変換ミスをしてしまいがちなので、この本では「戻り値」を使っています。
項番11.1.1練習問題p.209
1.「Hi!」と表示するhiメソッドを宣言してみましょう。
2.宣言したhiメソッドを呼び出してみましょう。
JShell
jshell> void hi(){System.out.println("Hello");} | 次を作成しました: メソッド hi() jshell> hi() Hello }
うむ!
次の練習問題p.211
1.greetingメソッドとまったく同じく、"Hello"に続いて受け取った引数を表示するメソッドをvoid salutation(String person)に続けて宣言してみましょう。
2.引数として数値を受け取って、その回数だけ「Hello」と表示するメソッドhellohelloを宣言してみましょう。hellohello(1)として呼び出すと「hello」、hellohello(2)として呼び出すと「hellohello」が表示されます。
3.hellohello(3)として呼び出して動きを確認してみましょう。
jshell> void salutation(String person){System.out.println("ご機嫌いかが?" + person + "さん");} | 次を作成しました: メソッド salutation(String) jshell> salutation("ミルクボーイ内海") ご機嫌いかが?ミルクボーイ内海さん jshell> void hellohello(int cnt){System.out.println("hello".repeat(cnt));} | 次を作成しました: メソッド hellohello(int) jshell> hellohello(3) hellohellohello
うむうむ!
次の練習問題 about 戻り値p.212
1.与えられた数字を2倍するメソッドをint dbl(intn)から始めて宣言してみましょう。
2.宣言したメソッドdblを呼び出してみましょう。
3.与えられた数字を3倍するメソッドtripleを宣言して呼び出してみましょう。
4.与えられた文字列を2回繰り返すメソッドを宣言して呼び出してみましょう。
5.与えられた2つの整数のうち大きいほうを返すメソッドmax2を宣言してみましょう。条件演算子を使います。
6.与えられた3つの整数のうち一番大きい数値を返すメソッドmax3を宣言してみましょう。
jshell> int dbl(int n){return n * 2;} | 次を作成しました: メソッド dbl(int) jshell> dbl(5) $9 ==> 10 jshell> int triple(int n){return n * 3;} | 次を作成しました: メソッド triple(int) jshell> triple(2) $11 ==> 6 jshell> string repeatStrs(String s){return s.repeat(2);} | 次を作成しました: メソッド repeatStrs(String)。しかし、 class stringが宣言されるまで、参照できません jshell> import java.lang.String jshell> string repeatStrs(String s){return s.repeat(2);} | 次を変更しました: メソッド repeatStrs(String)。しかし、 class stringが宣言されるまで、参照できません jshell> String repeatStrs(String s){return s.repeat(2);} | 次を置換しました: メソッド repeatStrs(String) jshell> repeatStrs("ふははは") $16 ==> "ふはははふははは" jshell> ing max2(int x,int y){ ...> int maxNum=0; ...> if(x > y){ maxNum = x;} ...> else if(y > x){ maxNum = y;} ...> return maxNum; ...> } | 次を作成しました: メソッド max2(int,int)。しかし、 class ingが宣言されるまで、参照できません jshell> int max2(int x,int y){ ...> int maxNum = 0; ...> if(x > y){maxNum = x;} ...> else if(y > x){maxNum = y;} ...> return maxNum; ...> } | 次を置換しました: メソッド max2(int,int) jshell> max2(10,100) $19 ==> 100 jshell> int max3(int x, int y, int z){ ...> int maxNum = 0; ...> if(x >= y){ ...> maxNum = x; ...> }else{ ...> maxNum = y; ...> } ...> if(z > maxNum){ ...> maxNum = z; ...> } ...> return maxNum; ...> } | 次を作成しました: メソッド max3(int,int,int) jshell> max3(59,17,97) $21 ==> 97
書き損じ多…汗
そして答え合わせ_φ( ̄ー ̄ )
うわあああmax3は、max2をもっとうまいこと作っといて利用すればよかったのだあああ。
あほ〜う(;ω;)
くっ…私やっぱ阿呆かしらん…と一瞬凹んだが、無駄な判断ほど無駄なものはないのだ。うむ。
次にいかそー
ブログは毎日は投稿できてないけど勉強0の日はゼロだぜ、
プロJava学習スタート以降は!うほっ
ぼちぼち寝よっ