- 投稿日:2020-10-27T22:00:43+09:00
Java SE Bronze 試験番号: 1Z0-818 (ループ文 編)(2020年10月)
公式サイト: Java SE Bronze
目的
Java Bronze SE 合格
目次
1, while文の使用
2, for文および拡張for文の使用
3, do-while文の作成と使用
4, ループのネスティング
公式サイト: The Java™ Tutorials1, while文の使用
while文 while(条件):条件がtrueである限り、無限ループします。
WhileDemo.javaclass WhileDemo { public static void main(String[] args) { int count = -10; while(count < 1) { System.out.println("Count is : " + count); count++; } } }2, for文および拡張for文の使用
for文
ForDemo.javaclass ForDemo { public static void main(String[] args) { for(int i = 0; i < 11; i++) { System.out.println("Count is : " + i); } }拡張for文
EnhancedForDemo.javaclass EnhancedForDemo { public static void main(String[] args) { int[] numbers = {1,2,3,4,5,6,7,8,9,10}; for(int item : numbers) { System.out.println("Count is : " + item); } } }3, do-while文の作成と使用
do-while文 条件に関わらず、一度は表示する。
DoWhileDemo.javaclass DoWhileDemo { public static void main(String[] args) { int count = 1; do { System.out.println("Count is : " + count); count++; }while(count < 11); } }4, ループのネスティング
ネスティング for文の中にfor文を記述。下記のソースコードは九九を表しています。
Nesting.javaclass NestingDemo { public static void main(String[] args) { for(int i = 1; i < 10; i++) { for(int j = 1; j < 10; j++) { System.out.print((i * j) + ","); } System.out.println(""); } }備考
1, データの宣言と使用 編
2, ループ文 編
- 投稿日:2020-10-27T13:33:26+09:00
【Java】Javaの3つの特徴
Javaの特徴
- オブジェクト指向
- Java仮想マシン
- ガベージコレクション
オブジェクト指向はデータを中心に考える
- そもそも本質はデータをどう加工するか、何をしたいのかはデータが中心に考える
- オブジェクト指向ではプログラムの中で扱う対象をモノ(オブジェクト)で表現
- アプリを構成するものは全てオブジェクトによって表現され、その組み合わせによってアプリを構成する
- データとその操作をカプセル/一体化してコードをかく
- よくやりがちな失敗は他のオブジェクトのデータを参照するメソッドを書き、他のオブジェクトのメソッドが別のオブジェクトのデータを参照してしまう
- オブジェクト1のメソッドが意味がなくなる→データオブジェクトという(凝集性が悪い)
- オブジェクト1のデータを参照するのはオブジェクト1のメソッドでないといけない
- 基本的にはデータとメソッドは一体化しよう!
Java仮想マシンはバイナリコード
C++
- PCに電気が入りCPUが動く
- CPUはマシン語で動いてる
- アセンブラ記述(C/C++)→コンパイル→マシン語(バイナリコード)
- アセンブラでかくとダイレクトにマシン語になる
- バイナリコードのみがCPUを直接動かすことができる
Java
- Java仮想マシンの上で動作
- CPUの上にJava仮想マシンを作る
- Java仮想マシンがCPUを直接動かせるバイナリコードである
- JDK、JREをインストールしないとJava仮想マシンが動かない
- Javaをコンパイルすると中間コードを吐き出す
- 中間コードはバイナリコードの上で動かす必要
- 中間コードを介するので直接CPUを動かすC++より遅い(と言われた)
- Javaなので遅いのではない
ガベージコレクションはメモリを自動で解放してくれる
CPU/メモリ(DRAM)/ストレージ(HDD/SSD)の構成
- CPU/DRAMは基盤上で足がくっついている
- データバス、アドレスバスでつながっている
- DRAMが保存できる容量は8byteとする
- アドレスバスは0-7までのどのアドレスにアクセスしたいか信号を出す
- データバスはその中身を出力
- CPU/メモリは1つの基盤の上に乗っている
- これとは別に直でつながってる
- アドレスバスにI/OポートというIO空間を指定するポートがついてる
- I/OポートにHDD/SSDがつながっている
- CPUと直接つながってないのがストレージ(HDD/SSD)、直接つながっているのがDRAM
- CPUが持っているメモリは電源がついてないと消える、HDDは磁性体に書き込むので電気を切っても残る
- メモリチップの種類
メモリの仕組み
- 例えばZ80の場合、
データバス8本+アドレスバス16本 (=CPUがアクセスしたい番地を示す)
- 0000 0000 0000 0000 ~ 1111 1111 1111 1111 までアクセスできる
- 8bitCPUのZ80の場合、0~65535番地まである
- Java仮想マシンはOSにメモリを使う使わないを要求する
- OSはメモリをブロックで管理する機能がある
- Java仮想マシンはOSに100byteのメモリを要求
- OSが管理している使ってない番地を仮想マシンに返す
- Javaはそのメモリを使うことができる
- メモリリーク: あるApplicationで仮想マシンが使うと指定して終わりを伝えず死ぬと100byte使ったままになってしまい、他の領域に使えない
- C/C++ではポインタを使いメモリアロケーターを使って割当、解放命令で解放してあげる
- Javaでは、提供するメモリはJDKのJavaマシン管理下
hoge = null;
と書くかJava仮想マシン終了で自動でガベージコレクションがメモリを解放してくれる
- 投稿日:2020-10-27T08:53:41+09:00
【Java】リクエストを投げて画面を表示(GET/POST)
GETメソッドでhello.htmlに画面遷移する
- ブラウザでURLを入力してエンターを押すと、GETメソッドを呼んで、ブラウザでHTMLページを取得する
- localhost:8080/helloへのGETリクエストに対する処理をgetHelloメソッドで行う
- メソッドの戻り値には拡張子なしのhtmlファイル名を指定
- htmlファイルは、resources/templatesフォルダーからのパスを指定
- localhost:8080/helloにGETリクエストが来るとhello.htmlを表示
@Controller
- コントローラークラス
- @Controllerアノテーションを付けることで、DIで利用できる
@GetMapping
- @GetMappingをメソッドに付けると、HTTPリクエストのGETメソッドを処理できるようになる
- Web UIを返すときはGetMappingを使う
HelloController.javapackage com.example.demo.trySpring; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class HelloController{ @GetMapping("/hello") public String getHello(){ return"hello"; //hello.htmlに画面遷移 } }hello.html<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <!--Thymeleafを使用するために記述--> <head> <meta charset="UTF8"></meta> <title>Hello World</title> </head> <body> <h1>Hello World</h1> <body> </html>URLにアクセスして確認!
POSTメソッドで画面から値を渡す
Namespace
- 名前空間とは対象のものをある名称で確実に識別・特定するためのもの
- HTML/XMLの場合、かっこをつかってタグやタイトルかく(
<h1><TITLE>
など)- Thymeleafでは以下のように独自のネームスペースを用意、
- 名前空間に含まれるSchema(あるシステムの構造を表すもの)を定義すると Thymeleaf固有のnamespaceを使うことができる
- th:value属性を使うことで、画面からコントローラークラスに値を渡すことができる。
//Xmlns:th = “URL” //定義先 <input type="text" name="text1" th:value="${text1_value}"/>
- hello.htmlにformタグを追加
hello.html<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF8"></meta> <title>Hello World</title> </head> <body> <h1>Hello World</h1> <form method="post" action="/hello"> 好きな文字を入力: <input type="text" name="text1" th:value="${text1_value}"/> <input type="submit" value="クリック"/> </form> <body> </html>使用メソッドをformタグのmethod属性で指定
- POSTメソッド用の処理をHelloControllerクラスに追加
@PostMapping
- POSTメソッドで送られてきた場合の処理を行う
@RequestParam
- メソッドの引数に@RequestParamアノテーションを付けることで、画面からの入力内容を受け取る
- アノテーションの引数には、htmlのname属性の値を指定
model.addAttribute
- model.addAttributeにキーと値をセットする
- 画面(html)から指定したキーの値を受け取ることができる
- この場合のModelについては下記の(注)参考
- キーバリューでデータを渡すことであらかじめ特定のクラスを作り込まなくていい=汎用性が高い
以下の例では、
- FormをクリックしたらPOSTが飛ぶ(postRequest)
- @RequestParamのアノテーションをつけることで
"text1"
を指定したstr
で受け取れる"sample"
というattribute名でstr
をセットHelloController.javapackage com.example.demo.trySpring; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; @Controller public class HelloController{ @GetMapping("/hello") public String getHello(){ return"hello"; } @PostMapping("/hello") public String postRequest(@RequestParam("text1")String str, Model model){ model.addAttribute("sample",str); //画面から受け取った文字列をModelに登録 return "helloResponse"; //helloResponse.htmlに画面遷移 } }コントローラークラスからの値を受け取る
src/main/resources/templates
配下に、helloResponse.html
を作成th:text
属性に、model.addAttribute
で登録したキーを指定する- SpringBootの決まりごととして、共通してModelクラスでAttributeという形で画面に表示したいデータを追加し、テンプレートをかきかえる
- テンプレートとモデルをマージした結果を返す
helloResponse.html<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF8"></meta> <title>Response Sample</title> </head> <body> <h1>Hello Response</h1> <!--Modelからの値を受け取り受け取った文字を表示--> <p th:text="${sample}"></p><body> </html>URLにアクセスして確認!
(注)Schemaとは
- 名前空間の中にスキーマが入っている
- データの構造のこと
- 一般的にはDBの名前とサイズ組み合わせ
- bigint userId
- Varchar[50] username
- HTML自体もスキーマである
- 標準タグの構成をHTMLのスキーマという
- 例:Aタグは外部リンク/ Div 汎用的な範囲を作るなど
- XML標準の名前空間にスキーマを追加することができる
- th:labeなどで名前空間を拡張することでスキーマ拡張できる(metaDBと言えるようなもの)
(注)Thymeleafのモデルとは
- ModelはData Transfer Objectのこと(今回のようにデータのみ渡す=データオブジェクト)
- Java側のコードでデータにアクセスする/Java側のデータを表すclassをHtmlのテンプレに埋め込みたい時にDataだけが入ったJabaのObjectを作って渡すのがModelのt役割
- 投稿日:2020-10-27T07:02:40+09:00
Flyweight パターンとConcurrentHashMap を Java で学ぶ
Java の知識をアップデートしようとして、Essential Java の第三刷を読んでいるのだが、
Flyweight
パターンが出てきた。そういえばこのパターンはちゃんとやったことがないので、理解して試してみることにした。Flyweight パターン
Flyweight パターンは、GoFのデザインパターンの一つで、次のような問題を解くためのパターンである。
- 多くのオブジェクトが効率的にサポートされる
- 多くのオブジェクトの生成を避けたい
定義
- 本質的なステートがシェアできる
- (本質的なステートを区別できる)ステートを投入するインターフェイスがある。
何かこれだけだとよくわからない。
シーケンスを見ると、どうやらキャッシュするパターンのようだ。歴史の項目を見てみると、ドキュメントエディタで使われたようで、フォントの情報とか、例えばアルファベットが26文字だとすると、その都度文字のインスタンスを生成していたら、インスタンスが大量に生成されてしまう。だから、26個だけインスタンスを生成するようにして、それをキャッシュして返す仕組みのようだ。
ギターフレットの音のサンプル
サンプルを作って理解してみよう。要はファクトリーのキャッシュしたものであるので、簡単だ。今回のお題は若干強引だが、ギターの弦の番号と、フレットの番号を入力すると、その場所の音を返すアプリケーションだ。音は12個しかないので、インスタンスは、12個でよいはず。デザインパターンのダイアグラムでいう
Flyweight
のオブジェクトとして、Sound
を使ってみる。Sound.java : Flyweight
package com.company; public interface Sound { void Play(); }SoundImpl : Flywieght1
package com.company; public class SoundImpl implements Sound{ private String note; public SoundImpl(String note) { this.note = note; } @Override public void Play() { System.out.println(note + "- ♪"); } public String getNote() { return note; } }SoundFactory : FlywieghtFactory
package com.company; import java.util.HashMap; public class SoundFactory { private static Map<String, Sound> sounds = new HashMap<String, Sound>(); public static Sound getSound(String note) { if (sounds.containsKey(note)){ return sounds.get(note); } else { Sound sound = new SoundImpl(note); sounds.put(note, sound); return sound; } } }Main が膨れ上がってかっこ悪いが、ともかく、動作するものが出来た。単純でポイントは、Factoryに Map を持たせて、キャッシュしておけば良い。簡単だ。
Main.java
package com.company; import java.util.HashMap; public class Main { private static HashMap<Integer, Integer> stringMap = new HashMap<Integer, Integer>(); private static HashMap<Integer, String> notes = new HashMap<Integer, String>(); private static void setup() { stringMap.put(1, 4); stringMap.put(2, 11); stringMap.put(3, 7); stringMap.put(4, 2); stringMap.put(5, 9); stringMap.put(6, 4); notes.put(0, "C"); notes.put(1, "C#"); notes.put(2, "D"); notes.put(3, "D#"); notes.put(4, "E"); notes.put(5, "F"); notes.put(6, "F#"); notes.put(7, "G"); notes.put(8, "G#"); notes.put(9, "A"); notes.put(10, "A#"); notes.put(11, "B"); } public static void main(String[] args) { setup(); while(true) { java.io.Console con = System.console(); if (con != null) { String input = con.readLine("string:fret:"); if (input.contains("exit")) { System.out.println("Closing ..."); System.exit(0); } else { String[] stringFret = input.split(":"); int openNote = stringMap.get(Integer.parseInt(stringFret[0])); int fret = Integer.parseInt(stringFret[1]); int note = openNote + fret; if (note >= 12) { note = note - 12; } String noteString = notes.get(new Integer(note)); Sound sound = SoundFactory.getSound(noteString); sound.Play(); } } } } }Concurrent だとどうなるのか?
本編が簡単だったので、Javaにあまり慣れていないので、もうステップやってみることにした。コンカレントな状態だと、どうすればいいのだろう?
HashMap
は、Thread Safe ではないらしい。Thread Safe にしたかったらHashTable
もしくは、ConcurrentHashMap
を使うと良いらしい。いったい何が違うのだろうか?
- Difference between HashMap and ConcurrentHashMap in Java Collection こちらの記事を元に整理してみたい。
HashTable と ConcurrentHashMap
HashMap
とConcurrentHashMap
の違いは、スレッドセーフか否か。つまりコンカレントの環境で使えるか否か。HashTable
が提供するレベルの同期レベルを提供できるではないが、実用では十分なれべるHashMap
は、Collections.synchronizedMap
でラップするとHashTable
とほぼ同等のコレクションが返される。それは、すべての更新イベントで、Map
全体がロックされる。ConcurrentHashMap
の場合は、スレッドセーフを全体のMapをパーティション分割して、一部だけロックするような仕組みになっている。ConcurrentHashMap
は、よりスケーラブルで、パフォーマンスもSynchronized HashMap
より良い。シングルスレッドの環境下では、HashMap
の方が、ConcurrentHashMap
よりパフォーマンスが良いこれらの比較を見てみると、明らかに
ConcurrentHashMap
を使うのが妥当なケースが多そうだ。じゃあ実装してみよう。Micronaut を使って実装する
簡単そうだ。
Micronaut install
私の環境では、
chocolatey
のソースが書き換わっていたので、デフォルトに戻す。 Administrator 権限で PowerShellを起動するとインストールできる。$ choco isntall micronaut -s https://chocolatey.org/api/v2/Generate project via template
次の感じで Maven のプロジェクトを生成できる。
$ mn create-app flyweight-server --build mavenまずはこれで、サーバーは上がるようになる。自分がハマったポイントは、自分は、IntelliJ を使ってコードを書くのだが、Terminal の JAVA_HOME が設定されていなくて、
Caused by: java.lang.IllegalArgumentException: invalid target release: 11
というエラーメッセージが出た。もともとは、Java8 の JDK だけパスにあったので、それが問題なのだが、Java の基本は、JAVA_HOME の設定と、%JAVA_HOME%/bin をパスに通すことだと改めて思いだした。そうでないと、ちゃんと maven が動作しない。$ cd flywieght-server $ mvn clean package $ java -jar .\target\flyweight-server-0.1.jarコントローラの追加
コントローラを追記してみる。Micronautは、どちらかというと、Spring の軽量版みたいな感じで様々な機能をサポートしている様子。私は今回 Http Server が欲しいだけだったので、マニュアルを見てコードを書いてみる。コントローラーとルーディングをするのは、単にコントローラを書けばよいみたい。とても簡単でござる。
FlyweightController.java
package flyweight.server; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller("/flyweight") public class FlyweightController { @Get(value = "/{string}/{fret}", produces = MediaType.TEXT_PLAIN) public String index(Integer string, Integer fret){ return "String: " + string + " Fret: "+ fret; } }これで動いたので、コントローラーの知りたい挙動は理解できた。次に Flyweight のアプリを改造してみよう。これは、マルチスレッドで動作すると思うので、先ほどの
ConcurrentHashMap
を使ってみよう。なんと先ほどのより短くなってしまったではないか。
computeIfAbsent
メソッドが、関数を受け取るようになってきて、アトミックな動作を保証してくれる。これは、C# の ConcurrentDictionary と同じ雰囲気だ。だから、もし、なかったら新たに作って返すし、そうでなければ、既存のものを返してくれる。最高!SoundFactory.java
package flyweight.server; import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class SoundFactory { private static ConcurrentMap<String, Sound> sounds = new ConcurrentHashMap<String, Sound>(); public static Sound getSound(String note) { return sounds.computeIfAbsent(note, n -> new SoundImpl(n)); } }全体像
FlyweightController.java
package flyweight.server; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; @Controller("/flyweight") public class FlyweightController { @Get(value = "/{string}/{fret}", produces = MediaType.TEXT_PLAIN) public String index(Integer string, Integer fret){ Integer openNote = Constants.stringMap.get(string.intValue()); int note = openNote.intValue() + fret.intValue(); if (note >= 12) { note = note - 12; } Sound sound = SoundFactory.getSound(Constants.notes.get(note)); return "String: " + string + " Fret: "+ fret + " Sound: " + sound.Play(); } }Constants.java
package flyweight.server; import java.util.HashMap; public class Constants { static HashMap<Integer, Integer> stringMap = new HashMap<Integer, Integer>(); static HashMap<Integer, String> notes = new HashMap<Integer, String>(); static void setup() { stringMap.put(1, 4); stringMap.put(2, 11); stringMap.put(3, 7); stringMap.put(4, 2); stringMap.put(5, 9); stringMap.put(6, 4); notes.put(0, "C"); notes.put(1, "C#"); notes.put(2, "D"); notes.put(3, "D#"); notes.put(4, "E"); notes.put(5, "F"); notes.put(6, "F#"); notes.put(7, "G"); notes.put(8, "G#"); notes.put(9, "A"); notes.put(10, "A#"); notes.put(11, "B"); } }Sound.java
package flyweight.server; public interface Sound { String Play(); }SoundImpl.java
package flyweight.server; public class SoundImpl implements Sound { private String note; public SoundImpl(String note) { this.note = note; } public String Play() { return this.note + "- note"; } public String getNote() { return this.note; } }Application.java
package flyweight.server; import io.micronaut.runtime.Micronaut; public class Application { public static void main(String[] args) { Constants.setup(); Micronaut.run(Application.class, args); } }実行結果
[INFO] Replacing original artifact with shaded artifact. [INFO] Replacing C:\Users\tsushi\Code\java\spike\micronaut\flyweight-server\target\flyweight-server-0.1.jar with C:\Users\tsushi\Code\java\spike\micronaut\flyweight-server\target\flyweight-server-0.1-shaded.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.444 s [INFO] Finished at: 2020-10-26T14:16:48-07:00 [INFO] ------------------------------------------------------------------------ PS C:\Users\tsushi\Code\java\spike\micronaut\flyweight-server> java -jar .\target\flyweight-server-0.1.jar ←[36m14:17:24.022←[0;39m ←[1;30m[main]←[0;39m ←[34mINFO ←[0;39m ←[35mio.micronaut.runtime.Micronaut←[0;39m - Startup completed in 1154ms. Server Running: http://localhost:8080今日は軽く
Flyweight
パターンと、ConcurrentHashMap
を学べたので良しとしましょう。Resource
- 投稿日:2020-10-27T01:10:51+09:00
Java SE Bronze 試験番号: 1Z0-818 (データの宣言と使用 編)(2020年10月)
公式サイト: Java SE Bronze
目的
Java Bronze SE 合格
目次
1, Java のデータ型(プリミティブ型、参照型)
2, 変数や定数の宣言と初期化、値の有効範囲
3, 配列(一次元配列)の宣言と作成、使用
4, コマンドライン引数の利用1, Java のデータ型(プリミティブ型、参照型)
プリミティブ型
byte
short
int
long
float
double
boolean
char参照型
String
2, 変数や定数の宣言と初期化、値の有効範囲
変数
Variable.javaclass Variable { public static void main(String[] args) { -- Primitive type -- byte a = 1; short b = 5; int c = 10; long d = 100L; float e = 1.0F; double f = 2.00; boolean x = true; boolean y = false; char z = 'A'; -- Reference type -- String name = "java"; } }定数 ※慣習的に大文字を使います
Constant.javaclass Constant { public static void main(String[] args) { -- Primitive type -- final int VALUE = 10; -- Reference type -- final String NAME = "java"; } }3, 配列(一次元配列)の宣言と作成、使用
Array.javaclass Array { public static void main(String[] args) { -- int type -- int[] numbers = {5, 10, 15, 20}; -- String type -- String[] subjects = {"Japanease", "Math", "Social", "Sience", "English"}; for (int i = 0; i < numbers.length; i++) { System.out.println(numbers[i]); } for (int i = 0; i < subjects.length; i++) { System.out.println(subjects[i]); } } }4, コマンドライン引数の利用
CommandLine> java "クラスファイル名" "値1" "値2" ...mainメソッドでは、Stringクラスの配列としてコマンドライン引数を受け取ります
CommandLine.javaclass CommandLine { public static void main(String[] args) { System.out.println(args[0]); System.out.println(args[1]); "よく使う命令実行文" "キーボードから1行の文字列の入力を受け取る" String s = new java.util.Scanner(System.in).nextLine(); "キーボードから1行の整数の入力を受け取る" int input = new java.util.Scanner(System.in).nextInt(); System.out.println(s); System.out.println(input); } }備考
アドバイスやコメントなどあればぜひお願いします
適時、加執修正します❗️
1, データの宣言と使用 編
2, ループ文 編