- 投稿日:2021-09-14T23:04:07+09:00
Basic operation of NIO Buffer classes
There are 4 internal indicators (capacity, limit, position, remaining) in Buffer classes, example below shows the change of these indicators. import java.nio.Buffer; import java.nio.ByteBuffer; public class BufferTest { public static void main(String[] args) { ByteBuffer buf = ByteBuffer.allocate(8); System.out.println("[new buf]"); printBufferInfo(buf); buf.put((byte) 1).put((byte) 2).put((byte) 3); System.out.println("[put 3 elements]"); printBufferInfo(buf); for (int i = 0; i < buf.position(); i++) System.out.println(buf.get(i)); System.out.println("[get 3 elements by index]"); printBufferInfo(buf); buf.flip(); System.out.println("[flip]"); printBufferInfo(buf); for (int i = 0; i < 2; i++) System.out.println(buf.get()); System.out.println("[get 2 elements]"); printBufferInfo(buf); buf.compact(); System.out.println("[compat]"); printBufferInfo(buf); buf.put((byte) 4); System.out.println("[put 1 element]"); printBufferInfo(buf); buf.clear(); System.out.println("[clear]"); printBufferInfo(buf); } public static void printBufferInfo(Buffer buf) { System.out.println("Capacity: " + buf.capacity()); System.out.println("Limit: " + buf.limit()); System.out.println("Position: " + buf.position()); System.out.println("Remaining: " + buf.remaining()); } } The output is [new buf] Capacity: 8 Limit: 8 Position: 0 Remaining: 8 [put 3 elements] Capacity: 8 Limit: 8 Position: 3 Remaining: 5 1 2 3 [get 3 elements by index] Capacity: 8 Limit: 8 Position: 3 Remaining: 5 [flip] Capacity: 8 Limit: 3 Position: 0 Remaining: 3 1 2 [get 2 elements] Capacity: 8 Limit: 3 Position: 2 Remaining: 1 [compat] Capacity: 8 Limit: 8 Position: 1 Remaining: 7 [put 1 element] Capacity: 8 Limit: 8 Position: 2 Remaining: 6 [clear] Capacity: 8 Limit: 8 Position: 0 Remaining: 8
- 投稿日:2021-09-14T19:41:57+09:00
(JAVA勉強用メモ)4. 制御構造
for文に関するtips for (int i = 0, j = 0; ; ) { } // 型が同じなら複数の変数を宣言できる for (int i = 0; ; i++, System.out.println("JAVA")) { } // 更新文で複数の処理を実行できる 拡張for文内の変数 拡張for文で要素を格納する変数は一時的なものなので、変数の参照先を変更しても集合には影響しない。 String[] ary = {"A", "B", "C"}; for (String str: ary) { str = "X"; } for (String str: ary) { System.out.println(str); // -> ABC }
- 投稿日:2021-09-14T17:43:59+09:00
【雑談】あえて今、20年前のJavaを自由に語る
はじめに 「10年前の技術」に関する記事。 こんなテーマなら、さらに20年前の話から始めて、私の思い出話を語ろうかなと思う。 この記事では、私が知っている時代の「Java」を自由に語る。 語ろうとしている年代(1990年代後半)、私は当時小学生であり、当然SEなんて仕事はしていなかったが、密かに「システムエンジニアになりたい」という夢を抱いていた。 そんな私にとってJavaは、「プログラミング言語として学んだ2番目の言語」であり、 長い期間きちんと独学していた言語でもあるので、思い入れがたくさんある。 当時からしてみれば、オブジェクト指向やガベージコレクション、AWT/SwingなどのGUIライブラリ(なお今は死語)は非常に画期的な機能の一つであった。 当時は「Javaは文法的にもかっちょいいし、Cよりは遅いけど色々ソフトウエアが作れる言語なんだぜ~」なんて世間の風潮だったわけ。 実際、当時はJavaアプリケーションやJavaアプレット(これも死語だな)が当時人気だったFlash並みにWebで量産されていき、人気があった。 そんな今、そんな姿はどこへやら、既得権益(Oracle社)に飲まれた言語となっている。 ところで、当時あれほど「ポンコツ」と称されていた(Javaとなんとなく似ているけど全く別物の)スクリプト言語JavaScriptは、今や「開発者が好む言語No.1」になる時代。 まさかこんな時代が来るなんて想像もしていなかった。 注意 ここに出てくるコードは、「20年前~15年前くらいのJavaのコード(を何となく思い出しながら書いたもの)」であり、化石のようなものだ。まず現代の設計に追いつかないものであるので、決して使用してはならない。 歴史に関する詳しい部分は不正確なので、例えば以下の良記事を参照にすること。当時の私は中学生~大学時代で、リアルで仕事しているわけではない。ビジネスや規格競争のような難しいことはようわからずにやってたからな。 本人も当時の状況を他の資料(Wikipediaなど)を使って割と不正確に伝えていますので、「これおかしい」とか「ここもっと調べて欲しい」ってのがあったら是非コメントください。 旧き良きJavaの遺産 20年前、Javaの黎明期 Duke 読者は、こいつの存在「Duke」を知っているだろうか。 ちなみに最近まで名前を知らなかった このマスコットキャラクター、実は既にJDK Beta(1995)の頃には誕生していた。 当然のことながら、よく売れている書籍の中でこいつが描かれていたら、間違いなくJavaの書籍であることを確実に伝えている。 どうやってJavaを勉強したか 私がJavaを勉強したのは、丁度JDK 1.0~1.1くらいの内容をまとめてくれたプログラマーの書籍からである。 今でも間違いなく現存しているホームページに「浅煎り珈琲 Javaアプリケーション入門」がある。(なお化石) 今でこそ、無料有料問わず色んな分野に対する書籍・Webサイト・動画が多量にある時代であるが、 当時の私からしてみれば、プログラミングの基本がここまできっちり理解できるコンテンツは貴重で、 私にとってのデータアーキテクチャの基礎を今でも支えてくれている。 家電とJava 実は開発当初、JavaはIoTの先駆けだったことをご存知だろうか? Javaは、当時として堅牢性を考慮した設計であり、同時にWeb技術への拡張性を兼ね合わせているため、 これをWebSocketを使ってHTTP/HTTPS/FTPプロトコルなどに接続してしまえば、あら不思議IoTモジュールの完成、そんな未来を描いた言語だったのだ。 Web技術の中心となった現代のJavaであるが、Javaは、元々家電の制御のために作られた技術であった。 それは、当時C++はあまりにも柔軟性がありすぎて制御の安定性に問題があり、現代ほど電気製品の制御に向いている技術ではなかったためである。 そこで、JavaはC++の概念を整備して堅牢性を重視して設計された。 Javaの概念は型制約の厳しさを残してC#に引き継がれている。 Java仮想マシン(JVM)と互換性 Java仮想マシンという概念も、現在で言うところのクロスプラットフォーム開発やVirtual Desktop、Dockerなどの仮想化環境の考え方のベースとなる素晴らしいものであった。 一般に、プログラムの実行される方式はインタープリタ方式とコンパイラ方式がある。 インタープリタ方式は、人間の書いたコードをそのまま実行する方式 コンパイラ方式は、人間の書いたコードを機械語に変換する方式 インタープリタ方式が現在の多数の高級言語に該当し、 コンパイラ方式の代表格がC++であることは言うまでもない。 そして、そのJavaは、どちらの方式でもない中間コード方式を取っていた。 これはコンパイルするときに、Java仮想マシン(JVM)に理解できる形式で変換するものであり、 それで生成された中間言語は、JVMが責任を以て実行するので、どのような環境でも実行出来る強みがあったのだ。 当然、家電のような組込み用途においても、このような設計が活用できるのが有意義には違いない。 Swing GUIに関しても規格化が行なわれるような流れとなっていて、JavaにおいてはSwingと呼ばれるライブラリが並んだ。 当時としてはLook&Feelに配慮された綺麗なGUIで、JVMの性質上どのようなプラットフォームでも動くのが強みだった。 実際、Swingの画面とmfcの画面を比較してもらえれば分かると思う。 mfcはC++でWindowsでしか書けないのに、よくも悪くもWindows的なGUIであるのに対し、Swingはこれがあらゆるプラットフォームで動くんだからすごいすごいってなると思う。 Swing GUIの規格化とレイアウトマネージャー さらに、このSwingとはちょっと違う話題だが、レイアウトマネージャの概念も、Javaをユニークにする一つの概念であった。 実はレイアウトマネージャに関してはきちんと対応したC#フレームワークは、WPFまで存在しないのだ。 つまり、当時のWindowsアプリケーションはほぼ例外なく絶対座標系でGUIを表示していた。 現在でもこの絶対座標系を禁止するような正式な解決策はなく、私もWindowsアプリ捨ててブラウザ使いたいって気持ちになってしまう。WPFめんどくせえんだよなあ そしてそのWPFも難しすぎるってんで、それをHTMLとJavaScriptで記載してアプリケーションを作れるようにしたelectron.jsが割といま元気であるけれども、こうした時代に来るまでMicrosoftで作られた製品がユニバーサルデザインを意識した設計になることはなかったのである。 (tkinterやQtを見ていると、もしかすると当時でもユニバーサルデザインに対応したものはあったかもしれませんが。) 特に、以下のようなGridBagLayoutと呼ばれるレイアウトは難しかったが非常に便利であった。 HTMLで言うところの <table> <tr> <td colspan=2>AA</td><td>BB</td> </tr> <tr> <td>1</td><td>2</td><td>3</td> </tr> </table> に対応している機能なのだが、多少その仕組みが複雑とは言えどのようなレイアウトも再現出来たのには一定の効果があったように思える。 また、同じGUIをカードを切るように前後ろに配置するCardLayoutと呼ばれるレイアウトも便利であった。 これも、現在のHTML5ではインラインで代用される概念だと思うが、こういうのがデフォルトについていたJavaはレイアウトの考え方に対しても素晴らしい部分があったと思う。 アプレットとFlash この時代を象徴するJavaで出来たものと言えばアプレットであるだろう。 けれど、実はJavaの中でアプレットは初期の頃はJavaの目玉技術として採用されていたものの、2017年にはもはや表示されなくなるなどの憂き目に遭っている。 それでも、当時はすごかったのだ。個人のHPにJavaアプレットが大量に生成された。 今ではJavaScriptを使えば容易にゲームくらい作れる時代(私にそんな力はないが)だが、当時流行したFlash同様、JavaはプラグインをHTMLに埋め込む形式として流行した。 ↑のような本が山ほどあった時代だったわけです Javaアプレットの最大の強みは、JVMが責任もってブラウザの動きを管理してくれたことになる。 今でこそフロントエンド⇔バックエンドという用語は一般的なものになっているが、当時こうしたゲームを作ろうと思ったらプラグインを埋め込む方式が主流なのであった。つまり基本はフロントエンド側で完結するスタイルなのである。 そんなアプレットのHTMLは、どこでもこんな感じに書籍に書いてあったわけだ。 <html> <title>Java Applet</title> <body> <applet src="myapplet.class" width=640 height=480> </applet> </body> </html> この書き方自体、今のJavaScriptのHTML5に通ずるところがある。 もちろんこんな感じでプラグインのプログラムを1個だけ設置するなんてのはないのだが、idやname、classを使って上手いこと識別子を与えて、そこに表示したいプログラムをダイレクトに組み入れる考え方は似通っているのだ。 Javaはモバイル開発の元祖 Javaといえば、Androidのモバイルアプリケーションの分野で未だに現役であるが、既にもうこの時代から「携帯に使おうか」の流れはあったのだ。本当、Javaは恐ろしい子。 当時のモバイルフレームワークは多数あったが、有名どころは CLDC MIDP(Mobile Information Device Profile) : Vodafone, au ezアプリ用途 Doja : Docomo i-modeアプリ用途 などであろう。 Vodafoneという単語自体が懐かしいな。私は結構長年まで、Vodafoneユーザであった。 私の記憶では、自分自身の演習の目的でMIDPを頻繁に使っていたので、それを思い出すためにソースコードがどんな感じだったか紹介すると、 WebではAppletと言うように、MIDPではMIDletと呼ばれるオブジェクトクラスを定義する。 めっちゃ懐かしいコードだと本気で思った() Javaにおいて、結構Appletが基本で派生したモバイル開発は多いのかなと印象。 また、このことでAppletで学んだ知識がそのまま大体Javaアプリ開発に活かせるのも大きなメリットだった。 一方、下記にもあるようにMIDletからオーバーライドしたメソッドでしか処理が出来ないので、設計に対する自由度はさすがに現代と比べるとかなり劣る。 Appletは、ブラウザのプラグインに埋め込んでいたのでその範囲の中では自由度が高かったのですが、モバイルアプリは「モバイルアプリの一つのウィジェット」だけが切り出されているせいで、出来ることが少なくて「使いにくいな~」という印象はどうしても残った。 またご存知のように、昔のガラケーは画像容量が少ない!ゲームとか作ろうとすると、画像リソースの問題にも限界が・・・。 import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class HelloMIDlet extends MIDlet implements CommandListener { public HelloMIDlet() { ...(GUI初期化処理)... } public void startApp() { ...(動作start時の処理 MIDletのオーバーライド)... } public void pauseApp() { ...(Pause時の処理 MIDletのオーバーライド)... } public void destroyApp(boolean unconditional) { ...(終了時の処理 MIDletのオーバーライド)... } public void commandAction(Command c, Displayable s) { ...(GUIで登録したEventListenerの処理 CommandListenerから継承)... } } javadocでドキュメント作成を簡単化 この記事をまとめている最中、重要なトピックであるjavadocのことを触れるのを忘れていた。 本当、書けば書くほどJavaのネタが出てくる。それだけ将来性が期待されていた言語なんだろうなって思う Javaを少しでもやっていれば、このAPI仕様書には必ずお世話になっているはずだ。 しかし、私の過去においては若干これはトラウマだ。 継承の概念も少しずつ学んでいく時期だったので、分からないクラスはとにかく索引から探す!!!なんていう無謀な作業に取り組んでいた記憶がある。 当時はひたすら検索をかけまくったので、Ctrl+Fはショートカットキーとして覚えろと言わなくても体が覚えてしまった。 ↑こんなところから探せとか言われたらマジで発狂する(なお現実) さてこのjavadocも、ソースコード管理上、大変画期的な仕組みである。 Sun Microsystems社の社員は、この膨大なJavaのライブラリに一つ一つWebページを用意し、機能説明を準備しただろうか? しかもリリース期間が1~2年という状況で。 当然そんなことはしないわけで、ソースコードにコメントの型を決めてそれを自動生成していたのだ。 javadocでマニュアルに追記する場合、例えばこんな感じで書いたりする (外部サイトより引用) public class Sample01{ /** * サイズの設定 * @param width 幅 * @param height 高さ */ public void setSize(int width, int height){ } } そしてコンパイルするときに、javac -d Sample01.javaなどと書いて実行すると、先ほどのAPI仕様書が自動生成されるのだ。 この考え方は特にJavaのプログラマーにとって本気で感動させられる仕様であった。 (もちろん現在では割と日常的なものであるのだが) API仕様書の作成の作業が一つ減り、コードレビューする際もこのjavadocを吐き出せばレビューが出来るのが素晴らしい。 Collection Framework Collection FrameworkはC++のSTLを真似したものであるが、これもJavaでは独自の仕様となった。 実際、JavaのSTLで採用されているVectorはC++をベースに設定された可変長配列であり、基本になっているようである。 ところが、当時Javaはジェネリクスが存在しなかった。 一応、可変長配列として有名なArrayListなんか ArrayList list = new ArrayList(); と書いていたのだが、型指定の難しさは課題にあったのだ。それで2005年のJ2SE 5.0以降のアップデートでジェネリクスが生まれていた。 ちなみにそういう面では、他言語とは多少出遅れている面もあったと思われる・・・と思いきや、全く同じ時期の2005年にC# 2.0が出来たのだが、この時点でC#はジェネリクスに対応していたようだ。 私の中では、C#でジェネリクスを積極的に扱えるようになったのは、LINQが誕生するC# 3.0だったように思える。 革命的な文法 (1) インスタンスを渡す インスタンスの概念は、C++の左辺値参照が基本となっている。そしてその左辺値参照はどうも1988年に構想され導入されたもので、この概念自体はC++がベースとなっているようだ。 しかし、C++の左辺値参照には「インスタンス」の概念はなく、実体がどこかにいなければそのデータは無効となる。 参照渡し(C++) // originalはSomeClass型の実体のあるデータ // 参照は常に実体を持たないといけない。 SomeClass& obj_ref = original; またインスタンスに近い概念であるポインタは、nullptrを許容するのでそれが制御上の問題に繋がる。 ポインタ渡し(C++) // nullptrが許容されてしまう SomeClass* obj_ref = nullptr; // つまり、途中でこのような処理がなければ実行時例外が起きる if( obj_ref == nullptr) { ...(処理)... } // originalはSomeClass型の実体のあるデータ // 参照は常に実体を持たないといけない。 obj_ref = &original; ところで、Javaのルールに基づいてインスタンスを発明したことで、抜本的にこの問題が解決されているのだ。 つまり、インスタンスはそこでは常に参照を渡し続けると出来るのだ。 インスタンスを渡す SomeClass obj = new SomeClass(); // ☆ obj2を生成するときに、objを参照渡し SomeClass2 obj2 = new SomeClass2(obj); だが私の印象だが、これが原因で、当時、C言語/C++を中心に開発してきたエンジニアは、JavaやC#、objective-Cなどのオブジェクト指向型の言語で挫折する傾向が強かったように思う。 ☆の部分で、まさかobjが変更される可能性があるとは思うまい。C++の言語的には、 SomeClass2* obj2 = new SomeClass2(obj); と書かれりゃ、 class SomeClass2 { public: SomeClass2(SomeClass obj) { ...(処理)... } ...(以下省略) }; と勘違いする人と、 class SomeClass2 { public: SomeClass2(const SomeClass& obj) { ...(処理)... } ...(以下省略) }; と何となく意識づけ出来る人と分かれてしまうからだ。 その対策として、C#では値クラスが導入されたり、C++でも構造体とクラスは別の役割をするように調整されたりしたわけだが、私の印象ではバリバリポインタを使ってくるエンジニアほど、ここのところは弱いという印象があった。 一つの障壁になってしまっていたのが、悲しい。 革命的な文法 (2) インタフェースとポリモーフィズム また、Javaにおいてインタフェースクラスも重要な文法表現である。 C++では、多重継承がサポートされている。 class SubClass : public SuperClassA, public SuperClassB { ...(実装)... }; この多重継承の最大の利点は、様々なクラスの型変換を許容することにある。このように書けば、 // originalはSuperClassAで生成されたオブジェクト auto obj1 = dynamic_cast<SuperClassA*>(original); と書くことを許容するが、このdynamic_castはSuperClassB*に対してはnullptrを返却する。 それをJavaでは、 一般的なクラスの多重継承は禁止とする。 多重継承はインタフェースのみ許容し、インタフェースに存在するメソッドは全て抽象化され、オーバーライドしないといけない。 のルールを追加した。このようにしたことで、 interface IntarfaceA { ...(実装)... } interface IntarfaceB { ...(実装)... } public class SubClass extends SuperClass implements InterfaceA, interfaceB { ...(実装)... } と書けるようになり、さらにポリモーフィズムに破綻せずに、 // originalはSubClass型のインスタンス interfaceA obj_a = original; interfaceB obj_b = original; とする記載を許容することが出来たのだ。 こうすることでの最大のメリットは、オブジェクト指向の基本的な考え方であるis-a関係を破綻させていないところにある。 GoFのデザインパターンも、is-a関係あってこそ成立するものである。デザインパターンがオブジェクト指向の基礎教材となり、色々なデータ構造を表現できるようになったのは言うまでもない。 これは大きなポイントであり、古きJavaを語る上でマルチスレッドやEventListenerを使うときに重要な部分となった。 EventListener型の発明 ~ Delegate型との大きな違い ~ このEventListenerを聞くのは、現在では一部のJavaScriptネイティブでやっている人しかいないと思われるが、これも非常に画期的な仕組みだった。どう画期的かと言うと、イベントリスナークラスを定義してそのGUIに登録するだけでイベントの挙動を表せてしまうわけだ。 確かに、この仕組みはややこしいものであったが、このことによりイベントを共通のオブジェクト化する考え方が一般的になったのもある。 GUIにActionListenerと呼ばれるインタフェースを用意しておき、そのインタフェースを継承したクラスを開発者が作り、それを登録する。 例えば同期のC#ではこうした設計をするとき、delegateを採用するだろう。Windows Formsの例であるが public partial class FormMain : Form { public FormMain() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("ボタンがクリックされました!"); } } という感じで、あくまでデザインビューワの中にbutton1_Clickを仕込ませて構成する。 ここで、フォームに存在するボタンGUIは別にメソッドOnClickを用意しておき、実際はdelegateでbutton1_Clickを実行するように仕事を投げる。 この仕組みは一見快適で、逆にWindowsアプリケーションの仕組みが楽すぎて、他のフレームワークに移行できない人が増えている原因になっているのだが、もう一つ大きな問題を抱えている。 それは「Formの実装の中に処理が潜んでしまうこと」だ。 つまりこうしたコードを書いてしまうと、MVPパターンで言うところのフォームのViewの中に、ボタンイベントであるPresenterの処理が混在してしまう。 技量がなくモジュール分割の習慣がついていないエンジニアなら、下手したらそのPresenterの中にModelとViewを一緒にごちゃ混ぜにして書く惨事すら招くのだ。もはやそんな状況では、MVPモデルなんて言うものは存在しないだろう。 それをJavaではEventListenerの形式で回避していて、 リスナークラス class MyActionListener implements ActionListener { MyApplet applet; public MyActionListener(MyApplet applet) { this.applet = applet; } //ActionListener インタフェースの実装 public void actionPerformed(ActionEvent e) { ...(Modelの処理やViewのプロパティに該当する値を変更する)... } } GUIクラス public class MyApplet extends Applet { private Button btnBlue; private MyActionListener actionListener; ... (略)... public void init() { btnBlue = new Button("blue"); actionListener = new MyActionListener(this); btnBlue.addActionListener(eh); } } こうすることで、少なくとも(Viewの一部+Modelの一部の処理)をListenerが、(Viewの処理)をAppletが担ってくれるようになるので、 設計が分かっていれば少しは上手く出来るようになる。 ただ、多分MVPモデルをきちっと意識して設計した人がいたかはかなり怪しい。解説書を読んでもそういうことには触れなかった。 実際、WPFが出てからMVVMに対する布教が進んできたという印象があるので、当時のプログラマーも要素分割の概念があったかはちょっと分からない。私は(当時)あくまでホビーユースだったから 10年前の自分に伝えたいこと 実は、こうした20年前の技術があったり、色々と画期的な設計を目指したJavaであったが、ある時期からそのJavaをやるのをやめたのであった。 その理由のきっかけは色々あるが、 Java 6からのアップデートがあまり行われなかったこと プラグインを使う方法がセキュリティセーフではなかったこと Oracle社の買収 などが挙げられる。 まあ、アルゴリズムの分野に関して言えばJavaで作られた成果物を結構見るし、それなりに上手く動くので、教育的な部分に関してはそれなりに使えた面はあったけれど、既に当時から限界な感じはちょっと見えていたのであった。 また、Javaを躍進させたモバイル開発の業界は確かに今も堅調だと思うのだけど、 少なくともPCを中心にやっていく私の世界だと、当面手を引かないといけない状況になっていたのも事実だ。 それが現在、安定期も終わり徐々に衰退期に近づいているような。 Oracle社が(アップデートを重ねることで)独自のDBシステムと共に既得権益化したこと、 openjdkはGPL化され、Javaで書いたコード以外のライセンス汚染が問題になること を誰が想像しただろうか? もし、私が10年前の自分にいえるとすれば、 「今すぐモバイル開発にさらに時間を集中させるか、C++の制御技術やパターン認識の知識をもっと深めろ」 と言っているかもしれません。 ちなみに 当時の記憶ですが、2008年頃、学校で勉強していたころ、Javaベースのモバイルウィジェット開発のフレームワークを作った「Jig.jp」さんというところがあります。 2008年といえば、Java SE 6が生まれた頃だったと思います。 今でこそJavaベースのモバイルアプリ開発はごく日常的なことだと思いますが、 よーく考えたら、2008年の時点でJavaがモバイルウィジェットの概念の発想が出来るかもと注目した人は、なかなか素晴らしい着眼点を持っていたかもしれません。
- 投稿日:2021-09-14T17:43:51+09:00
Java11の時代に実装されたSpring BootのアプリケーションはJava17でもworkするのか
これはなんですか 俺はJava11をやめるぞジョ○ョー! 長いから結論を先に書いておきます。 つこてるライブラリがものによってはworkできない。 諸元 Java https://jdk.java.net/17/ JDK 17 Release-Candidate Builds (2021-08-06) arch: macOS/x64 PC Darwin bb.local 20.6.0 Darwin Kernel Version 20.6.0: Wed Jun 23 00:26:31 PDT 2021; root:xnu-7195.141.2~5/RELEASE_X86_64 x86_64 MacOS Big Sur version 11.5.2 Spring Bootその1(軽めのやつ) Spring Boot 2.5.0 実装されたJavaのclass及びinterface 40個くらい Dependencies [INFO] +- org.springframework.boot:spring-boot-starter-actuator:jar:2.5.0:compile [INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.5.0:compile [INFO] +- org.springframework.boot:spring-boot-starter-web-services:jar:2.5.0:compile [INFO] +- org.springframework.boot:spring-boot-starter-security:jar:2.5.0:compile [INFO] +- org.mybatis.spring.boot:mybatis-spring-boot-starter:jar:2.1.3:compile [INFO] +- mysql:mysql-connector-java:jar:8.0.25:runtime [INFO] +- org.springframework.boot:spring-boot-configuration-processor:jar:2.5.0:compile (optional) [INFO] +- org.projectlombok:lombok:jar:1.18.20:compile (optional) [INFO] +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.5.0:provided [INFO] +- org.springframework.data:spring-data-commons:jar:2.5.1:compile [INFO] +- org.springframework.boot:spring-boot-starter-test:jar:2.5.0:test [INFO] +- io.springfox:springfox-swagger-ui:jar:2.8.0:compile [INFO] +- io.springfox:springfox-core:jar:2.8.0:compile [INFO] +- io.swagger:swagger-annotations:jar:1.5.21:compile [INFO] +- org.springdoc:springdoc-openapi-ui:jar:1.5.4:compile [INFO] +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.12.3:compile [INFO] +- org.openapitools:jackson-databind-nullable:jar:0.2.1:compile [INFO] +- ch.qos.logback:logback-core:jar:1.2.3:compile [INFO] +- ch.qos.logback:logback-access:jar:1.2.3:compile [INFO] +- net.rakugakibox.spring.boot:logback-access-spring-boot-starter:jar:2.7.1:compile [INFO] +- com.amazonaws:aws-java-sdk:jar:1.11.980:compile [INFO] +- com.amazonaws:aws-java-sdk-logs:jar:1.11.980:compile [INFO] +- com.amazonaws:aws-java-sdk-ec2:jar:1.11.980:compile [INFO] +- com.j256.cloudwatchlogbackappender:cloudwatchlogbackappender:jar:2.1:compile [INFO] +- com.googlecode.json-simple:json-simple:jar:1.1.1:compile [INFO] +- org.flywaydb:flyway-core:jar:7.7.3:compile [INFO] \- io.github.yoshikawaa.modelmapper.spring.boot:modelmapper-spring-boot-starter:pom:0.1.0:compile [INFO] \- io.github.yoshikawaa.modelmapper.spring.boot:modelmapper-spring-boot-autoconfigure:jar:0.1.0:compile [INFO] \- org.modelmapper.extensions:modelmapper-spring:jar:2.3.5:compile [INFO] \- org.modelmapper:modelmapper:jar:2.3.5:compile 手順 openjdkのサイトから対象のtar.gzを取得し下記に解凍 curl https://download.java.net/java/GA/jdk17/0d483333a00540d886896bac774ff48b/35/GPL/openjdk-17_macos-x64_bin.tar.gz tar -xfvz openjdk-17_macos-x64_bin.tar.gz -C /Library/Java/JavaVirtualMachines Macにインストールしてあるjdkを切り替える $HOME/.bashrc JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-17.jdk PATH=$JAVA_HOME/bin:$PATH:~/development/flutter/bin:~/Library/Android/sdk/bin:~/Library/Android/sdk/tools/bin:~/Library/Android/sdk/platform-tools:/usr/local/opt/python@3.8/libexec/bin 確認 bb:~ yamamotodin$ java -version openjdk version "17" 2021-09-14 OpenJDK Runtime Environment (build 17+35-2724) OpenJDK 64-Bit Server VM (build 17+35-2724, mixed mode, sharing) よし・・ IntelliJの設定 IntelliJに対しJDKを追加する プロジェクトで使うJDKを17にする(一瞬警告が出たような気がするけど見落とした・・) グルグルボタン押してmaven設定の読み込み直し後、maven clean。 起動しよう spring-boot-run org.modelmapper:modelmapper:jar:2.3.5 で起動できないエラー。 [io/github/yoshikawaa/modelmapper/spring/boot/autoconfigure/ModelMapperAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.modelmapper.ModelMapper]: Factory method 'modelMapper' threw exception; nested exception is org.modelmapper.ConfigurationException: ModelMapper configuration errors: 1) Failed to instantiate proxied instance of jp.n-resolution.project.transaction.history.repository.entity.TransactionHistoryEntity. Ensure that jp.n-resolution.project.transaction.history.repository.entity.TransactionHistoryEntity has a non-private constructor. これと同じ問題? modelmapperへダイブ! java.lang.IllegalStateException: size = 2 なんだろこれ・・ メソッドが2つあるからダメ? 文脈的にコンストラクタのことかな・・? だめだわからん。 別方向から攻める意味でほんとに対応してるのかどうかを見るため、changelog を参照 https://github.com/modelmapper/modelmapper/blob/master/CHANGES.md 2.3.6 New Features Supports Java 13 dependency見ると2.3.5....か・・・ java17とかサポートされてなさそうっすね。 というわけで現状ではmodelmapper関連がworkしないを結論とします。 もしmodelmapperを使いたいならこの辺(io.github.yoshikawaa.modelmapper.spring.boot:modelmapper-spring-boot-starter:pom:0.1.0 )の依存を外して、modelmapperをauto configure無しのつるしで組むようにすること。 おそらくjava12か13あたりからworkしてなかったと思われる。 でも本家modelmapperのchangelogにjava17に正式対応したって話は書いてないので、差し替えても動くかどうかは未知数。 新規プロジェクトで modelmapperの最新版にして試してみるか・・ というわけで、現状では既存プロジェクトに対するjdkのアップデートはやらない方向にします。 なお、Spring Bootそのものはjava17でも動作することを確認しているので、純粋に使ってるライブラリによる事情であることを申し添えます。 この先はかすれていてよめない。
- 投稿日:2021-09-14T16:32:20+09:00
Java イメージをPDFに変換
前の記事では、PDFからほかの様々なファイル形式に変換する方法を紹介しましたが、今回はイメージをPDFに逆変換する方法を紹介したいと思います。もちろん、Spire.PDFというライブラリを必要としますよ。下記の通り、ご案内申し上げます! 下準備 1.E-iceblueの公式サイトからSpire.PDF for Javaをダウンロードしてください。 2.IDEを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire.PDF.jarを参照に追加してください。 import com.spire.pdf.PdfDocument; import com.spire.pdf.PdfPageBase; import com.spire.pdf.graphics.PdfImage; public class ImageToPDF { public static void main(String[] args){ //PdfDocument オブジェクトを作成します。 PdfDocument pdf = new PdfDocument(); //新規ページを追加します。 PdfPageBase page = pdf.getPages().add(); //イメージを追加します。 PdfImage image = PdfImage.fromFile("Hydrangeas.jpg"); double widthFitRate = image.getPhysicalDimension().getWidth() / page.getCanvas().getClientSize().getWidth(); double heightFitRate = image.getPhysicalDimension().getHeight() / page.getCanvas().getClientSize().getHeight(); double fitRate = Math.max(widthFitRate, heightFitRate); double fitWidth = image.getPhysicalDimension().getWidth() / fitRate; double fitHeight = image.getPhysicalDimension().getHeight() / fitRate; page.getCanvas().drawImage(image, new Rectangle2D.Double(0, 0, fitWidth, fitHeight)); //保存します。 pdf.saveToFile("ConvertImageToPDF.pdf"); } } 実行結果
- 投稿日:2021-09-14T10:44:01+09:00
[paiza]スキルチェック見本問題 Java 数値演算結果で分岐/ 0 が含まれていないか判定 return sc.closeとは
初めに 今回もpaizaの見本問題(ランクD)に2問挑戦しました。 新たに、「return」 「sc.close」について学べましたので、 まとめていきます。(記事の後半) 易数値演算結果で分岐 (paizaランク D 相当) 整数 A, B, C が与えられます。 式 A × B ≦ C が成立している場合はYESを、 そうではない場合はNOを出力してください。 解答コード import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int a = sc.nextInt(); int b = sc.nextInt(); int c = sc.nextInt(); if(a*b<=c){ System.out.println("YES"); }else{ System.out.println("NO"); } } } 難0 が含まれていないか判定 長さ N の数列Aが与えられます。 Aの中に 0 が含まれていない場合はYESを、 0 が含まれている場合はNOを出力してください。 正解のコード import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] a = new int[n]; for (int i = 0; i < n; i++) { //配列に格納します a[i] = sc.nextInt(); } //拡張for文を使用し配列の中身を取り出します。 //0を見つけたら、sc.closeでスキャナーを閉じます。=0見つけたら終わる //returnで呼び出し元に処理を戻す for (int x : a) { if (x == 0) { System.out.println("NO"); sc.close(); return; } } System.out.println("YES"); sc.close(); } } この場合、出力結果は以下のようになります。 NO sc.closeとreturnがなかったらどうなる? 出力結果は以下のようになります。 NO YES returnとは? メソッドから呼び出し元に値を返します。さらに、return文が実行されると、 それ以降の処理は行いません。 sc.closeとは? スキャナを閉じてくれます。 参考記事 終わりに 拡張for文が苦手です。
- 投稿日:2021-09-14T03:16:48+09:00
inheritdocを調査する
はじめに Visual Studio 2019 version 16.4 Release Notes によると, 継承関係にあるクラスやメソッドには, 親のコメントを引き継いでクイック情報窓に表示するようになりました. inheritdocタグで明示することもできます. inheritdocタグを明示した場合, 警告CS1591は出力されません. また, 16.4より前のリリースと出力されるXMLドキュメントは変わりません. いつからかはわかりませんが, inheritdocタグの補完がされるようになりました (Visual Studio 2017では候補にでない). ここから, コメントからドキュメントを生成することに興味のない方には関係がありません. inheritdocタグに対応, だけ見て"16.4より前だから対応していないらしい, コメントもそのままコピーしよう", とならない方がよいでしょう. Sandcastle Sandcastleは, C#コンパイラが生成したXMLからドキュメントを生成するシステムのひとつです. 継承先にコメントがない場合は取り込む, ある場合はリンク先を見てね, のような動作をするようです. コメントから直接イメージできるドキュメントにはならない印象です. namespace Inheritdoc { /// <summary> /// Something /// </summary> public interface ITweetAlert { /// <summary> /// This method does something0 /// </summary> void Method0(); /// <summary> /// This method does something1 /// </summary> void Method1(); } /// <inheritdoc /> public class TweetAlert : ITweetAlert { public virtual void Method0() { } /// <inheritdoc /> /// <summary> /// TweetAlert implements Method1 /// </summary> public virtual void Method1() { } } } Javadoc 何も考えなくても美しいドキュメントが生成される印象です. /** * Something */ interface ITweetAlert { /** * This method does something0 */ public abstract void Method0(); /** * This method does something1 */ public abstract void Method1(); } class TweetAlert implements ITweetAlert { @Override public void Method0() { } /** * {@inheritDoc} * TweetAlert implements Method1 */ @Override public void Method1() { } } Javadocは継承先にコメントがない場合, 親のコメントを継承しますが, 注釈をつけてくれます. Method0 public void Method0() インタフェースからコピーされた説明: ITweetAlert This method does something0 定義: Method0 インタフェース内 ITweetAlert Method1 public void Method1() This method does something1 TweetAlert implements Method1 定義: Method1 インタフェース内 ITweetAlert Doxygen Doxygenでは, 設定 INHERIT_DOCSをYESにすると, メソッドのコメントを親から引き継ぎます, クラスのコメントは引き継ぎません. デフォルトでは, コメントのない要素のドキュメントは生成しなかったりと設定を細かく行う必要があります. copydocコマンドで明示することもできます. copydocにメソッドを指定する場合, オーバーロード解決のために引数リストも指定します. /** @brief Something */ class ITweetAlert { public: /** @brief This method does something0 */ virtual void Method0() =0; /** @brief This method does something1 */ virtual void Method1() =0; }; /** @copydoc ITweetAlert */ class TweetAlert : public ITweetAlert { public: virtual void Method0() override { } /** @copydoc ITweetAlert::Method1() TweetAlert implements Method1 */ virtual void Method1() override { } }; TweetAlert::Method1()のドキュメントは次のようになります. copydocコマンドでコピーしたドキュメントの次に, ピリオドが追加されます. 理由は不明です. This method does something1. TweetAlert implements Method1 Implements ITweetAlert. まとめ コメントからドキュメントを生成するシステムのほとんどは, 継承も考慮して設計されています. オーバーライドしているかはナウい言語ではコードに書くことができますから, タグを明示的に書くかどうかは好みだと思います. 実装側にコメントを書かなければならないとしたら, 設計ミスの匂いがしますし. 複数個所に同じコメントを書くことはやめましょう.
- 投稿日:2021-09-14T01:24:33+09:00
[Java基礎⑦]文字列の比較 equals メソッド [paiza]スキルチェック見本問題 単純な条件分岐 Java編
初めに 今回、以下の問題に挑戦し、Javaでの文字列と文字列の比較について学びました。 普通に比較演算子を使用したところ不正解になってしまいました。 (以下は見本問題のため、問題、解答コードの公開は自由です。) 文字列Sが与えられます。Sがpaizaと一致する場合はYESを、 一致しない場合はNOを出力してください。 誤答 文字列の比較演算子に注意! 標準入力をlineで受け取り、==の比較演算子を使い、 "paiza"と一致するかをif文で条件分岐させました。 しかしこれだと不正解です。 (line == "paiza")が成立してくれません。 import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String line = sc.nextLine(); if(line == "paiza"){ System.out.println("YES"); }else{ System.out.println("NO"); } } } 問題点 比較演算子ではオブジェクトを比較する 問題は(line == "paiza")の箇所です。 配列や文字列を比較する場合、比較演算子を使用すると、 同じオブジェクトを参照してればtrue、違えばfalseが返ってきます。 //同じオブジェクトを参照している場合には、 //比較演算子で比較するとtrueが返って来る String line1 = "paiza"; String line2 = line1; if(line1 == line2) → true 今回比較すべきなのは、「値」です。 入力された「値」がpaizaに等しいかどうかです。 使うべきは equalsメソッド 現状、(line == "paiza")としてる箇所は、 if (line.equals("paiza")とすることで、値の比較になります。 正解のコード import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String line = sc.nextLine(); if(line.equals("paiza")){ System.out.println("YES"); }else{ System.out.println("NO"); } } } 参考にしたサイト
- 投稿日:2021-09-14T01:24:33+09:00
[Java基礎⑦]文字列の比較 比較演算子とequals メソッドの違い [paiza]スキルチェック見本問題 単純な条件分岐 Java編
初めに 今回、以下の問題に挑戦し、Javaでの文字列と文字列の比較について学びました。 普通に比較演算子を使用したところ不正解になってしまいました。 (以下は見本問題のため、問題、解答コードの公開は自由です。) 文字列Sが与えられます。Sがpaizaと一致する場合はYESを、 一致しない場合はNOを出力してください。 誤答 文字列の比較演算子に注意! 標準入力をlineで受け取り、==の比較演算子を使い、 "paiza"と一致するかをif文で条件分岐させました。 しかしこれだと不正解です。 (line == "paiza")が成立してくれません。 import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String line = sc.nextLine(); if(line == "paiza"){ System.out.println("YES"); }else{ System.out.println("NO"); } } } 問題点 比較演算子ではオブジェクトを比較する 問題は(line == "paiza")の箇所です。 配列や文字列を比較する場合、比較演算子を使用すると、 同じオブジェクトを参照してればtrue、違えばfalseが返ってきます。 //同じオブジェクトを参照している場合には、 //比較演算子で比較するとtrueが返って来る String line1 = "paiza"; String line2 = line1; if(line1 == line2) → true 今回比較すべきなのは、「値」です。 入力された「値」がpaizaに等しいかどうかです。 使うべきは equalsメソッド 現状、(line == "paiza")としてる箇所は、 if (line.equals("paiza")とすることで、値の比較になります。 正解のコード import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String line = sc.nextLine(); if(line.equals("paiza")){ System.out.println("YES"); }else{ System.out.println("NO"); } } } 参考にしたサイト