- 投稿日:2020-08-23T21:48:55+09:00
ギャラリーから画像を選択し表示するAndoroidアプリ
この記事は、株式会社富士通システムズウェブテクノロジーが企画する「いのべこ夏休みアドベントカレンダー 2020」の22日目の記事です。
(お約束)本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。はじめに
Andoroid Studioで画像を選択し画面に表示するソースを書いたので、本記事ではそのソース、手順などを紹介します。
背景
前回の記事(Google Cloud Vision APIを使って食べ物の写真を判定してみる)を踏まえ、選択した写真をAPIで判定するアプリを作ってみようと思い、1段階目として、ギャラリーから画像を選択する部分を記事にしました。
事前準備
下記に関しては今回のアドベントカレンダー16日目の記事「Androidアプリ「HelloWorld」を作って、好き勝手に弄ってみた」で記載されているので参照していただければと思います。ここでは省略します。
・Andoroid Studioのインストール
・プロジェクトの新規作成
・エミュレーターの作成と起動エミュレーターの日本語化
おそらくデフォルトで英語になっているので、日本語化します。
エミュレーター上で[Settings]画面を表示し、[System]-[Languages & input]-[Languages]の順に選択します。
Englishだけ表示されていると思うので、[Language preferences]から日本語を選択すると、Englishの下に日本語が表示されるので、ドラッグで順番を入れ替えることで日本語化完了です。エミュレーター上に画像を保存する
画像選択をするために、画像をエミュレーターで確認できるようにします。
方法としては2つ
・エミュレーターに画像をドラッグ&ドロップ
DownLoadのフォルダに画像が入ります。
・Device File Explorerでアップロード
[View]-[Tool Windows]-[Device File Explorer]で開きます。
任意のフォルダで右クリックでファイル追加可能です。ソース
ボタン押下でギャラリーを開き、選択した画像を画面に表示させます。
ギャラリーを開く
Intent intent = new Intent(Intent.ACTION_PICK, Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent, 1);
Intent(アクションの種類, 対象のアプリ)
startActivityForResult(インテント, リクエストコード)
Intentクラスで別のアプリでアクティビティを開始できます。
今回は、ギャラリー(画像一覧)を開いて選択した画像を取得しています。Intentに関する詳細は一般的なインテントを参照。
引数に指定している内容はざっくりと以下のような意味です。
・Intent.ACTION_PICK :データから選択したものを返すアクション
・Media.EXTERNAL_CONTENT_URI :画像データが取得できるURI
※「EXTERNAL_CONTENT_URI」はSDカード等の外部ストレージを参照します。内部ストレージの場合は「INTERNAL_CONTENT_URI」にすればよいみたいです。startActivityForResultのパラメータで指定するリクエストコードは遷移元を判断するためのものです。
ここでは、1をハードコーディングで指定していますが、定数等で管理するのがいい気がします。選択結果を表示する
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1 && resultCode == RESULT_OK && null != data) { ImageView imgView = findViewById(R.id.imageView); BufferedInputStream inputStream = null; try { inputStream = new BufferedInputStream (getContentResolver().openInputStream(data.getData())); imgView.setImageBitmap(BitmapFactory.decodeStream(inputStream)); } catch (FileNotFoundException e) { e.printStackTrace(); } } }「onActivityResult」メソッドは前段の「startActivityForResult」の実行結果を受け取ります。
選択した結果を画面のImageViewに設定します。また、引数のrequestCodeは「startActivityForResult」メソッドで指定したリクエストコードが返ってきます。
前段で述べた通り、遷移元を判断できるので下記のような書き方ができます。public void button1_onClick(View view) { Intent intent = new Intent(Intent.ACTION_PICK, Media.INTERNAL_CONTENT_URI); startActivityForResult(intent, 1); } public void button2_onClick(View view) { Intent intent = new Intent(Intent.ACTION_PICK, Media.INTERNAL_CONTENT_URI); startActivityForResult(intent, 2); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1) { // button1用の処理 } else if (requestCode == 2) { // button2用の処理 } }画面
上記までのソースをエミュレーターで実行すると、当初目的の「画像を選択し画面に表示する」ができました。
①ボタンを押下する
②③画像を選択
④選択した画像を表示最後に
Andoroid Studioを初めて使いましたが、Form系アプリとソースが似ていたので、大きく苦労はしませんでした。
次回はAndoroidアプリからCloud Vision APIを呼び出すところをやってみたいです。
- 投稿日:2020-08-23T17:51:12+09:00
Java Programmer Gold SE 8 資格まとめ(Java に慣れてる人向け)
記事の目的
Java Programmer Gold SE 8 試験に出題される内容をまとめました。
「昔から Java をやっているけど SE8 のことは微妙に知らない」というニッチな層向けです。この記事を書いたきっかけ
先日 Java SE 8 Programmer II (1Z0-809) を受験して合格し、Oracle Certified Java Programmer, Gold SE 8 をゲットしました。
Java2 の時に一度取得しましたが、今の世間で必要とされている知識レベルとは明らかに乖離していたので、自分の知識をアップデートする意味でも勉強し直した次第です。Android 開発でも SE8 の知識は必須となりつつありますしね。
受験にあたって試験範囲を自分なりにまとめたものがあるのですが、試験終了とともにそのままお蔵入りさせるのも忍びないので、記事というかたちで残しておこうと思いました。どなたかのためになれば、大変嬉しく思います。要点まとめ
Java の基本
数値リテラルの接頭辞
数値の先頭に付加される接頭辞によって何進数の数値かが決定する
- "0b"…2進数
- "0"…8進数
- なし…10進数
- "0x"…16進数
final変数を初期化するタイミング
final 修飾子を付与したインスタンス変数は、コンストラクタで初期化されていなくてはならない
イニシャライザやコンストラクタによる初期化の順番
オブジェクトの初期化に関わる処理は以下の順番で実行される
- static イニシャライザ
クラスのロード時- インスタンスイニシャライザ
インスタンス生成時、コンストラクタ実行前
変数を宣言しただけでは実行されない。インスタンス化が必要- コンストラクタ
列挙値の継承とインターフェイスの実装
- 列挙型のメソッドである
name()とtoString()は自身の文字列表現を返すname()は final なのでオーバーライド不可。toString()は可- 列挙型はインターフェイスの実装と、抽象メソッドの定義ができる。これらをした場合、各列挙値でオーバーライドする必要がある
- 文字列から列挙値を得る場合、
valueOf()メソッドが利用できる列挙値についての注意点
- 列挙値にはコンストラクタを定義できるが、new によるインスタンス化は許可されていないので、コンストラクタに public や protected をつけるとコンパイルエラーになる
何もつけなければコンパイルは通るが、new することはできない(コンパイルエラーになる)- final 宣言のないフィールドを定義すると、そのフィールドの値は任意のタイミングで変更することができる
enum Direction { North(0), South(1); // final 宣言しなければ、利用する側でこの値を変更できる int index; private Direction(int index) { this.index = index; } } // Direction の index フィールドを変更してみた例 Direction d = Direction.North; System.out.println(d.index); // 0 d.index = 10; System.out.println(d.index); // 10hashCode() と equals()
- 複数のオブジェクトを同値とする条件は下記2点
hashCode()の戻り値(ハッシュ値)が同じequals()が true- コレクションでの重複チェックは以下の通り。両者が成立したら同値とみなされる
- ハッシュ値が同じかチェック
- ハッシュ値が同じものだけを対象に
equals()で比較hashCode()を実装する場合、同値のオブジェクトからは値が返るよう実装するequals()の引数は Object。レシーバと同じ型にするとオーバーライドは成立せず、オーバーロードが成立してしまう。コンパイルエラーにはならないインターフェイスのメソッド
- インターフェイスに定義するインスタンスメソッドは public な抽象メソッドであればよい。abstract などの記述があってもコンパイルは通る
- 複数のインターフェイスに同名の default メソッドが定義されている状況で、両方を継承または実装すると default メソッドが競合してコンパイルエラーになる
ただし、継承または実装する側で default メソッドをオーバーライドするとエラーは解消するinterface Sample { // "public abstract"が有っても無くてもコンパイルは通る public abstract void execute(); } interface A { default void execute() { System.out.println("A"); } } interface B { default void execute() { System.out.println("B"); } } interface C extends A, B { // このコメントを外すとコンパイルエラーが解消する // default void execute() { System.out.println("C"); } }オーバーライドが成立するための条件
- メソッドをオーバーライドする際、戻り値はスーパークラスの型と同じかそのサブクラスでなければいけない
- メソッドのオーバーライドは、以下が一致しなければ成立しない。順番が一致しなくてもオーバーロードとなる
- メソッド名
- 引数の型
- 引数の順番
- static メソッドや static フィールドもサブクラスで再定義できる
ただしオーバーライドではなく「隠蔽」なので、super キーワードを使って親の static メソッドを呼び出すことはできないメソッドローカルのクラス
- メソッドローカルなクラスからメソッド内の変数を直接参照できるが、変数は実質的に final でないとダメ。final 宣言が無くても、メソッドローカルクラスから参照すると自動的に final 扱いになる。これはラムダも同様
- コンストラクタでメソッドの変数をメソッドローカルなクラスに与える場合は、元の変数を直接参照しないので final にしなくてもよい
- メソッドローカルなクラスからメソッドの外側のクラスのメンバ変数を参照する場合も、そのメンバ変数を変更して構わない
ラムダ式
- 引数のデータ型は省略可
- 引数が1つなら『()』が省略可
- 右辺の式が1つなら、右辺からの戻り値があっても無くても『{}』が省略可
- 右辺の式が1つで、かつ戻り値を返すなら return が省略可
関数型インターフェイス
Function 関連
インターフェイス メソッド 戻り値の型 Function<T, R>apply(T t)R UnaryOperator<T>apply(T t)T BinaryOperator<T>apply(T t1, T t2)T BiFunction<T, U, R>apply(T t, U u)R Consumer 関連
インターフェイス メソッド 戻り値の型 Consumer<T>accept(T t)void BiConsumer<T, U>accept(T t, U u)void Predicate 関連
インターフェイス メソッド 戻り値の型 Predicate<T>test(T t)boolean BiPredicate<T, U>test(T t, U u)boolean Supplier
インターフェイス メソッド 戻り値の型 Supplier<T>get()T プリミティブ型を受け取る関数型インターフェイス
- int、long、double の3つにはそれぞれ専用の関数型インターフェイスが存在する
boolean にも BooleanSupplier だけ は存在するSupplier、UnaryOperator、BinaryOperatorのメソッド名は下記に従う
ルール:【メソッド名】As【データ型】
例:applyAsInt、getAsBooleanなど
データ型 Function Consumer Predicate Supplier UnaryOperator BinaryOperator int IntFunction<R>IntConsumerIntPredicateIntSupplierIntUnaryOperatorIntBinaryOperatorlong LongFunction<R>LongConsumerLongPredicateLongSupplierLongUnaryOperatorLongBinaryOperatordouble DoubleFunction<R>DoubleConsumerDoublePredicateDoubleSupplierDoubleUnaryOperatorDoubleBinaryOperatorboolean - - - BooleanSupplier- - プリミティブ型を返す関数型インターフェイス
インターフェイス名 メソッド 説明 ToIntFunction<T>applyAsInt(T t)T型の値から int を返す ToIntBiFunction<T, U>applyAsInt(T t, U u)T型とU型の値から int を返す ToLongFunction<T>applyAsLong(T t)T型の値から long を返す ToLongBiFunction<T, U>applyAsLong(T t, U u)T型とU型の値から long を返す ToDoubleFunction<T>applyAsDouble(T t)T型の値から double を返す ToDoubleBiFunction<T, U>applyAsDouble(T t, U u)T型とU型の値から double を返す メソッド参照
- 関数型インターフェイスの中だけで使える
- 引数を取る場合は static メソッド参照と同じ書き方にする
コレクション
Arrays#asList
Arrays#asListで生成されるリストは、引数に与えられた配列を参照しているだけ。元の配列に加えた変更もリストに反映されるArrays#asListで生成されるリストはArrayList<E>と 互換性がない。 キャストしても失敗するコレクションクラスの性質と見分け方
Listは原則インデックスの順番SetとMapはクラス名のプレフィクスによって性質を見分ける
Linkedで始まるクラスは、挿入した順序が保たれるTreeで始まるクラスは自然順などによってソートされる。自然順で並べると 数字→英字(大)→英字(小) となるQueue インターフェイスの性質
- 挿入/削除/検査のメソッドが2種類あり、メソッドの実行に失敗した時の挙動が違う
- 例外が発生
- 挿入 …
add(E)- 削除 …
remove()- 検査 …
get()- null を返却
- 挿入 …
offer(E)- 削除 …
poll()- 検査 …
peek()- インデックスで要素にアクセスできない
Deque インターフェイスの性質
Queueとの違いは、 Double Ended Queue の名前通り、先頭または末尾に要素を挿入または削除できること
- 例外が発生
- 挿入 …
addFirst(E),push(E)/addLast(E)- 削除 …
removeFirst()/removeLast()- 検査 …
getFirst(),pop()/getLast()- null を返却
- 挿入 …
offerFirst(E)/offsetLast(E)- 削除 …
pollFirst()/pollLast()- 検査 …
peekFirst()/peekLast()Queueと同じで、インデックスでは要素にアクセスできないjava.util.concurrentパッケージにあるQueueインターフェイスの拡張にはタイムアウトを設定できるメソッドもある
常に待ち時間が発生する訳ではなく、挿入や削除ができないとき待機が発生するDequeの実装であるArrayDequeには null を入れることができないジェネリクス
ジェネリクスと型パラメータ
- クラスに対して型パラメータを宣言する場合、以下の用途で型パラメータは使用できない
- static メンバ
- new 演算子によるインスタンスや配列の生成
instanceofによる型の検証.classの参照- 型パラメータが適用されたメソッドを使うときは型を明示してもしなくてもよい
- 総称型の構文は以下の通り
class クラス名<型パラメータ(, 型パラメータn)> {...}- クラス宣言で型パラメータを使う場合、extends キーワードは使えるが super キーワードは使えない
- メソッドの構文は以下の通り
宣言: <型パラメータ> 戻り値型 メソッド名(型 引数名) {...}
使用: レシーバ.<型パラメータ>メソッド名(型 引数名) {...}
ワイルドカード
- ワイルドカードは
"*"ではなく"?"("*"はKotlin)- ワイルドカードを class 宣言の型パラメータに使うことはできない
- ワイルドカードの型は実行されるまで確定しないので、ワイルドカードを使って中のデータ型を指定したリストに追加するとコンパイルエラーになる
例外として<? super XXXXX>で宣言されたリストに XXXXX と同じ型のオブジェクトを入れることはできる- ワイルドカードを使った場合、宣言されている内容から判断できる範囲で問題がなければコンパイルエラーにはならない。型に互換性がないことが明確になったら、コンパイルエラーになる
型パラメータにワイルドカードを使った場合にコンパイルエラーが起きるところ
- 型パラメータにワイルドカードを使用すると、 実際にオブジェクトを追加するところ でコンパイルエラーになる
Comparable と Comparator
Comparable インターフェイス
java.langパッケージに所属- 比較される対象になるためのインターフェイス
Comparableで実装すべきメソッドはcompareTo(T o)のみ。比較相手より小さい場合は負の値を返し、等しい場合はゼロを、大きい場合は正の値を返す- クラス宣言時に
Comparable<T>の型パラメータに与えるのはcompareToが引数に取るオブジェクトの型Comparator インターフェイス
java.utilパッケージに所属- 比較するためのインターフェイス。なお比較対象は
Comparableインターフェイスを実装しているものに限らないComparatorで実装すべきメソッドは以下の2つ(equalsは任意)
compare(T t1, T t2)equals(T o)compare(T t1, T t2)では、t1がt2より大きい場合は正の値、t1とt2が等しい場合はゼロ、t1がt2より小さい場合は負の値を返すStream API
要素数が有限のストリームを生成
Collection#stream()->Stream<E>Arrays#stream(E[] array)->Stream<E>Arrays#stream(int[] array)->IntStreamArrays#stream(long[] array)->LongStreamArrays#stream(double[] array)->DoubleStreamStream#of(E… values)->Stream<E>Stream#empty()->Stream<E>IntStream#of(int… values)->IntStreamLongStream#of(long… values)->LongStreamDoubleStream#of(double… values)->DoubleStreamIntStream#range()/IntStream#rangeClosed()->IntStreamLongStream#range()/LongStream#rangeClosed()->LongStreamBufferedReader#lines()->Stream<String>java.nio.file.Files#lines()->Stream<String>要素数が無限のストリームを生成
どちらも
java.util.stream.Streamのメソッド
generate(Supplier<T> supplier)
supplier から提供される要素を無限に保持するStreamを生成するiterate(T seed, UnaryOperator<T> f)
seed が最初の要素で、それ以降は前の要素に f をかけ合わせた要素を無限に保持する Stream を生成するストリームの終端操作
- 同じストリームへの終端操作は1度だけ。複数回行うと
IllegalStateExceptionが発生する- 中間操作を呼び出しただけでは何も実行されず、終端操作を呼び出さない限り何も行われない。終端操作を呼び出すと全ての処理が実行される
- パイプライン処理では、ストリーム内の要素が1つずつ順番に全ての中間/終端操作を実行されてから次の要素が処理される
つまり 「要素1の中間操作×m→要素1の終端操作」⇒「要素2の中間操作×m→要素2の終端操作」⇒…⇒「要素nの中間操作×m→要素nの終端操作」 という順番Stream#reduce の戻り値
Stream#reduceはStreamの中身を集約するためのメソッド。第1引数に初期値を設定するほうのメソッドでは、戻り値がOptionalじゃない
reduce(BinaryOperator op)… 戻り値はOptional<T>reduce(T initial, BinaryOperator op)… 戻り値は T戻り値が Optional の終端操作
- 戻り値が
Optionalになるのは以下のメソッド
findAny()… 実行するたびに結果が変わる可能性があるfindFirst()… 何度実行しても同じ結果が得られるmin()max()reduce(BinaryOperator op)Streamの型によってOptionalの型が違う。例えばfindAny()なら以下の通り
Stream#findAny()…Optional<T>IntStream#findAny()…OptionalIntLongStream#findAny()…OptionalLongDoubleStream#findAny()…OptionalDoubleOptional のインスタンスを生成する
Optional#of(T value)… valueにnullは入れられないOptional#ofNullable(T value)… valueにnullを入れられるOptionalInt#of(int value)OptionalLong#of(long value)OptionalDouble#of(double value)Optional#ifPresent と Optional#isPresent
- 値があるかどうか(null or not null)を判定するためのメソッドは以下の2つ
isPresent()… 値の有無を判定するifPresent(Consumer)… 値があればConsumerを実行するOptional から値を取り出すためのメソッドは複数存在する
Optional<T>から値を取得するメソッドは以下。値が存在する場合はその値が得られるが、存在しない場合の挙動が異なる
get()
存在しない場合はNoSuchElementExceptionorElse(T)
存在しない場合は引数を返すorElseGet(Supplier<T>)
存在しない場合はSupplierから返される値を返すorElseThrow(Supplier<X extends Exception>)
存在しない場合はSupplierから返される例外をスローする特定のデータ型に特化した Optional の種類
Optional<T>の関連クラスと値を取り出すためのメソッドは以下
Optional<T>#get()OptionalInt#getAsInt()OptionalLong#getAsLong()OptionalDouble#getAsDouble()Stream と XXXStream の型変換
- 同じ
Stream型同士の変換はmap()Stream<T>型への変換はmapToObj()IntStream型への変換はmapToInt()LongStream型への変換はmapToLong()DoubleStream型への変換はmapToDouble()Stream#collect() メソッドと Collector クラス
collect()はStream内の要素を集約して、1つのオブジェクトを取得するメソッドCollectorsクラスは用途に合うCollectorインターフェイスの実装を提供する
その性質上、Streamクラスの一部メソッドと役割がかぶる例外
Error、Exception、 RuntimeException
- 全て
Throwableのサブクラスで、java.langパッケージに所属ErrorとExceptionはThrowableのサブクラスRuntimeExceptionはExceptionのサブクラス(Throwableの孫クラス)try〜catchが必須となる checked 例外はRuntimeException以外のExceptionのサブクラスだけ例外を catch する順番
- 例外はサブクラスから順番に catch すること
- スーパークラスをサブクラスより先に catch するとコンパイルエラーになる
※実行時エラーではない例外のマルチキャッチ
- 継承関係のある複数の例外をまとめてキャッチするとコンパイルエラー
- マルチキャッチしたときの例外オブジェクトは暗黙的に final 扱いになり再代入は不可
マルチキャッチでない場合は、final 扱いにならない例外の rethrow
- 1つのメソッドが複数種類の例外オブジェクトを catch して rethrow する場合、
throwsおよびcatchメソッドで取る例外は一致しなくてもよい- catch で起こりうる全ての例外の親クラスを拾って、そのまま throw する場合など
// SE7以降では、2つの例外をまとめて catch してもよい // executeからthrowされるのも、Exceptionではなく IllegalAccessExceptionとArighmeticException private void execute(int number) throws IllegalAccessException, ArithmeticException { try { switch (number) { case 1: throw new IllegalAccessException(); case 2: throw new ArithmeticException(); default: System.out.println("No exception"); } } catch (Exception e) { throw e; } }例外をthrowするメソッドのオーバーライド
throws宣言つきのメソッドをサブクラスでオーバーライドする場合、オーバーライドしたメソッドにthrows宣言をするかどうかは自由- オーバーライドしたメソッドでも
throwsを宣言する場合の例外は、元のメソッドと同じかそのサブクラスでなければならないRuntimeExceptionとそのサブクラスは無条件でthrowsに指定できる。ただし非チェック例外なので、呼び出し元で catch しなくてもコンパイルは通るtry〜with〜resources 文
try〜with〜resources文でのみtry単体での使用が可能- 使用するリソースは
java.lang.AutoCloseableか、そのサブインターフェイスであるjava.io.Closeableを実装する必要があるAutoCloseable/Closeableはどちらもclose()にthrows宣言があるため、リソースに使う場合もtryの中で使う場合も、例外を catch しないとコンパイルエラー
AutoCloseable#close() throws ExceptionCloseable#close() throws IOExceptionAutoCloseableもしくはCloseableのclose()で例外が発生したら、catch で補足されるtryブロックとリソースのクローズの両方で例外が発生したら、close()で起きた例外は抑制された例外として catch された例外オブジェクトにThrowableの配列で格納され、getSuppressed()で取得が可能try〜with〜resources文で例外が起きたときの実行順序は以下
tryブロック- 宣言した逆順にリソースをクローズ(下記のコードだと、Nから1へ順番に閉じる)
- catch ブロック
finallyブロック// (1) -> ResourceNから1の順番にclose() -> (2) -> (3) の順に実行 try (Resource1; Resource2; ...; ResourceN) { (1) } catch (Exception e) { (2) // getSuppressed() で撮れるのは Throwable の配列 for (Throwable th : e.getSuppressed()) { ... } } finally { (3) }アサーションとその利用方法
- アサーションは、
assert文で false が検出されたらAssertionErrorを投げる機能で、文法は以下の通りassert boolean式: エラーメッセージ;- boolean 式は括弧で括っても括らなくてもOK
- エラーメッセージは省略可
- アサーションはデフォルトでは無効。java コマンドで "-ea" オプション("enable assertion" の略?)を明示的に指定しないと、AssertError はスローされない
- 明示的に無効にするには、java コマンドで "-da" オプション("disable assertion" の略?)を指定する
- アサーションの対象だと明示したいなら
java -ea:【クラス名】として、コロン区切りでアサーションの対象(-daなら非対象)を指定するDate and Time API
クラス一覧
LocalDate… 日付LocalTime… 時刻LocalDateTime… 日付+時刻OffsetTime… UTC/GMTからの差分を「+hh:mm」で含む時刻OffsetDateTime… UTC/GMTからの差分を「+hh:mm」で含む日付&時刻ZonedDateTime… UTC/GMTからの差分をタイムゾーンIDで含む日付+時刻
- 全て
Temporalインターフェイスを実装する。更にそのスーパーインターフェイスはTemporalAccessor- "Local〜" と "Offset〜" と "Zoned〜" の違いは、同じ日時を表現する方式の違い
LocalDateTime#toLocalDate()とLocalDateTime#toLocalTime()でそれぞれへの変換が可能- 月を取得できるメソッドは2つ
getMonth()…Month列挙値で取得getMonthValue()… int 値で取得列挙型一覧
Month:月を表す
JANUARY,FEBRUARY,MARCH, …,DECEMBERDayOfWeek:曜日を表す
SUNDAY,MONDAY,TUESDAY, …,SATURDAYLocalDate / LocalTime / LocalDateTime のインスタンス化
now()of(year, month, dayOfMonth, ...)
それぞれのクラスが扱える値を引数にしてインスタンスを生成する
引数 month には整数でなくMonth列挙値をセットしてもOK
LocalDateTimeのみLocalDateとLocalTimeを引数に取るオーバーロードがある。年、月、日、時、分、秒、ミリ秒を引数に取るのもあるparse(String)、parse(String, DateTimeFormatter)
文字列からインスタンスを生成
DateTimeFormatterを併用すると任意のフォーマットの文字列でも可LocalDate#of および LocalTime#of のオーバーロード
LocalDate#ofには2つのオーバーロードメソッドがある。どちらも年月日は指定するが、それ以外の違いは以下の通り
- 第2引数が int
- 第2引数が
Month列挙値LocalTime#ofには3つののオーバーロードメソッドがあり、全て時分は指定するが、それ以外の違いは以下の通り
- 時分のみ
- 時分に加えて秒を指定
- 時分に加えて秒とナノ秒を指定
java.time.format.DateTimeFormatter
ofPattern(String)
フォーマットパターンを指定ofLocalizedDate(FormatStyle)
日付のフォーマット方式を指定ofLocalizedTime(FormatStyle)
時間のフォーマット方式を指定ofLocalizedDateTime(FormatStyle)
日時のフォーマット方式を指定ofLocalizedDateTime(FormatStyle, FormatStyle)
日時のフォーマット方式を、日付と時間で別々に指定- static で事前定義されたフォーマッタ
BASIC_ISO_DATEなどjava.time.format.FormatStyle
FormatStyleは4種類
FormatStyle.FULL
タイムゾーンを含む完全な書式。ゾーン情報を持たない LocalDateTime などに適用すると実行時に例外FormatStyle.LONG
タイムゾーンを含む簡潔な書式。ゾーン情報を持たない LocalDateTime などに適用すると実行時に例外FormatStyle.MEDIUM
タイムゾーンを含まない簡潔な書式FormatStyle.SHORT
タイムゾーンを含まない簡潔な日時までの書式LocalDateTime dateTime = LocalDateTime.of(2020, 8, 14, 9, 54, 30); ZonedDateTime zDateTime = ZonedDateTime.of(dateTime, ZoneId.systemDefault()); // FormatStyle.FULL … 『2020年8月14日 9時54分30秒』 println(fmt1.format(zDateTime)); // FormatStyle.LONG … 『2020/08/14 9:54:30 JST』 println(fmt2.format(zDateTime)); // FormatStyle.MEDIUM … 『2020/08/14 9:54:30』 println(fmt3.format(dateTime)); // FormatStyle.SHORT … 『20/08/14 9:54』 println(fmt4.format(dateTime));Date and Time API のフォーマット文字列
- "y" … 年
- "M" … 月(大文字)
- "d" … 日
- "H" … 時(大文字)
- "m" … 分
- "s" … 秒
- "S" … ミリ秒(大文字)
- "n" … ナノ秒
日付/時刻の加減算
加算 …
plus(TemporalAmount amountToAdd)
減算 …minus(TemporalAmount amountToSubtract)
PeriodやDurationがTemporalAmountインターフェイスを実装するplusYearsやplusWeeksなど個々のフィールドに対する加減算も可能だが、複数のフィールドをまとめて扱う場合はPeriodやDurationを引数にして plus を呼び出す夏時間
- 夏時間の適用開始日(時間を進める日)と適用終了日(時間を戻す日)は、同じ地域でも毎年異なる。ただし時刻は 02:00 で一定
- 適用が開始されると、オフセットが1時間減り時刻が1時間進む
02:00 から1時間進むので、01:59 の1分後は 03:00 になる
適用開始日に 01:00 と 03:00 の間隔を取ると、2時間ではなく1時間- 適用が終了すると、オフセットが1時間増え時刻が1時間戻る
02:00 から1時間戻るので、01:59 の1分後は 01:00 になるPeriod:年月日
toString()した Period 表現は "P00Y00M00D" となる
先頭の "P" は "Period" の頭文字Periodのインスタンスを生成する方法はいくつかある
betweenメソッドで2つのLocalDateやLocalDateTimeの差分を取るofYears(1)など ofXXXXX メソッドで生成。ただしメソッドチェーンは不可Periodは年、月、日、週で加減算できる
加減算のメソッドは plusXXXXX / minusXXXXX。plusYears(1)など
plusWeeks(3)で週を加算すると "P21D"。週のPeriod表現が無い為LocalDate/LocalDateTimeはplus/minusメソッドでPeriodを引数にして日付の加減算ができる// Period を使った年の加算 LocalDateTime dt = LocalDateTime.now(); Period p = Period.ofYears(1); // これは以下の2行と同等(メソッドチェーンは意味がない) // Period p1 = Period.ofDays(1); // Period p = Period.ofYears(2); Period p = Period.ofDays(1).ofYears(2);Duration:時分秒
toString()したDuration表現は "PT00H00M00S" となる
先頭の "PT" は "Period of Time" の略称Durationのインスタンスを生成する方法はいくつかある
betweenメソッドで2つのLocalDateTimeやLocalTimeの差分を取るofHours(1)など ofXXXXX メソッドで生成of(1, ChronoUnit.HOURS)など of メソッドでChromeUnitを併用して生成Durationは日、時、分、秒、ミリ秒、ナノ秒で加減算できる
日を加算したら PT24H で、ミリ秒以下だと PT0.13S となるLocalTime/LocalDateTimeはplus/minusメソッドでDurationを引数にして時分秒の加減算ができるjava.time.Instant
- エポック時間からの経過を表現するクラス
- インスタンスを生成する方法はいくつかある
Instant#now()Instant#ofEposSecond(long)Instant#ofEpocMilli(long)LocalDateTime#toInstant(ZoneOffset)ZonedDateTime#toInstant()LocalDateTime#toInstantでZoneOffsetが必要なのはLocalDateTimeにタイムゾーンの情報が含まれていない為Instantのタイムゾーンは常にUTC入出力
java.io.Reader を使った読み込み
Reader
public int read()
読み込んだ1文字を返す。末尾に到達したら -1public int read(char[] buffer)public int read(char[] buffer, int offset, int length)
読み込んだ文字を配列の一部または全部に入れて文字数を返す。末尾に到達したら -1BufferedReader
public String readLine()
読み込んだ1行のテキストを返す。末尾に到達したら nulljava.io.Writer を使った書き込み
Writer
public void write(char[] buffer)public void write(char[] buffer, int offset, int length)
配列の一部または全部を書き込むpublic void write(int c)
1文字書き込むpublic void write(String str)public void write(String str, int offset, int length)
文字列の一部または全部を書き込むBufferedWriter
public void newLine()
改行文字を書き込むjava.io.Reader や java.io.InputStream の読み込み位置制御
skip(long bytes)
現在位置から指定したバイト数だけ読み飛ばすmark(int readAheadLimit)
現在位置をマークしてreset()で戻れるようにする。引数は マークを維持しつつ読み込むことができる文字数の上限reset()
mark()した位置に戻る// ファイルの中身は "01234567" // 実行結果は "025676" try (BufferedReader br = new BufferedReader(new FileReader("sample.txt"))) { for (int i = 0; i < 3; i++) { br.skip(i); // iバイトを読み飛ばす System.out.print((char)br.read()); } br.mark(3); // 現在位置("6"のあるINDEX=5の場所)をマーク System.out.print(br.readLine()); br.reset(); // マークした位置(INDEX=5の場所)に戻る System.out.println((char)br.read()); } catch (IOException e) { e.printStackTrace(); }java.io.PrintWriter
java.io.Writerのサブクラスで、プリミティブ型をそのまま出力できる
boolean/char/char[]/int/float/long/String/Object が対象println以外にformatを使って文字列のフォーマットが可能- 自動フラッシュ機能を持つ
- 同じ機能を持つクラスに
PrintStreamがある
JDK1.2でPrintWriterにとって変わられたが、後方互換のため残っているjava.io.Console
- 標準入力からデータを読み取る
System#console()でシングルトンインスタンスを取得。 利用不可なら null が返るreadLine()で、入力された文字列を String で取得readPassword()で、入力された文字列を char[] で取得。パスワードの読み取りなので、入力時に文字列は表示しないwriter()とreader()で、それぞれコンソールに紐づいているPrintWriterとReaderを取得できるConsole自身にもprintfとformatメソッドがあり、コンソールに文字列を出力できるシリアライズに関する注意点
java.io.Serializableインターフェイスを実装したクラスはシリアライズ可能- シリアライズ対象外になるのは以下のどちらか
- static 変数
- transient 宣言されているメンバ変数
- スーパークラスがシリアライズ可能なら、サブクラスもシリアライズ可能
- デシリアライズでは、インスタンス初期化ブロックも、コンストラクタも呼び出されない。ただし static 初期化ブロックは呼び出される
また、以下のケースならスーパークラスのコンストラクタだけは呼び出される
- 自身は
Serializableだが、スーパークラスがSerializableではない- スーパークラスに引数なしのコンストラクタがある
- サブクラスのコンストラクタで明示的に親のコンストラクタを呼び出していない
- メンバ変数のシリアライズ可否は、フィールドではなく中身のデータ型で決まる
変数の型が何であれ、中身がSerializableならシリアライズ可能NIO2
java.nio.file.Path(特徴)
- 以下のメソッドで生成
Paths#get(String, String...)FileSystem#getPath(String, String...)- 主な特徴は以下の通り。
java.io.Fileにない機能を備える
- ファイルやディレクトリのパスを扱う
- ファイル属性(オーナー、パーミッションなど)の取得や変更が可能
- シンボリックリンクを扱える
- ファイル作成など、ディレクトリで発生したイベントの変更や監視が可能
java.io.Fileとの相互変換が可能
File#toPath()Path#toFile()java.nio.file.Path(メソッド)
getRoot()
パスのルートを返す。相対パスで生成した Path からは nullsubpath(int start, int end)
ルートを除く、インデックスで指定された範囲を抜き出した Path を生成するgetName(int)
ルートを除く、インデックスで指定された部分を String で返すrelativize(Path)
引数までの相対パスを返すresolve(String)、resolve(Path)
パスを解決する。引数によって戻り値となる Path は異なる
- 引数が相対パス … レシーバーに引数を連結して返す
- 引数が絶対パス … 引数をそのまま返す
- 引数が空 … レシーバー自身を返す
resolveSibling(String)、resolveSibling(Path)
レシーバーの親に対してパスを解決する。引数によって戻り値となる Path は異なる
- 引数が絶対パス…レシーバーに引数を連結して返す
- その他…レシーバーに引数を連結して返す
normalize()
「.」や「..」など冗長な部分を除去して適切な形に変換したパスを返すString sp1 = "/tmp/work1/sample.txt"; String sp2 = "/tmp/work2/dummy.txt"; Path p1 = Paths.get(sp1); Path p2 = FileSystems.getDefault().getPath(sp2); println(p1.getRoot()); // "/" println(p1.subpath(0, 2)); // "tmp/work1" println(p1.relativize(p2)); // "../../work2/dummy.txt" println(p1.getName(0)); // "tmp" Path rp = p1.resolve("../dat"); println(rp); // "/tmp/work1/sample.txt/../dat" println(rp.normalize()); // "/tmp/work1/dat" // Windows の場合 Path wp = Paths.get("C:¥¥temp¥¥work¥¥sample.txt"); println(wp.getRoot()); // "C:¥"java.nio.file.FileSystem
ファイルシステムへのインターフェイスを提供する。
FileSystemsクラスの static メソッドで取得
FileSystems#getDefaultFileSystems#getFileSystemFileSystems#newFileSystemjava.nio.file.Files(ファイル操作)
以下は全て static メソッド
copy
ファイルやディレクトリのコピー
- ディレクトリの中身まではコピーされない
- コピー先に同名のファイルが存在する時 CopyOption で上書き指定が無ければ例外
- デフォルトの挙動ではファイルをコピーしても属性はコピーされない
- CopyOption を指定せずにシンボリックリンクをコピーすると、リンクが示す実体がコピーされる
- 引数に与えるパスはコピー/移動をする場所ではなく、移動/コピー後のパス
move
ファイルやディレクトリの移動。挙動は copy の1〜5と同じgetAttribute(Path, String, LinkOption...)
ファイルの属性値(ファイルサイズや更新日時など)を読み取るStream<String> lines(Path)List<String> readAllLines(Path)
ファイルの全ての行を返す。メソッドによって戻り値の型が異なるjava.nio.file.Files(ディレクトリの操作)
以下は全て static メソッド
createDirectory()
ディレクトリを作成するが、親は作成しないcreateDirectories()
親も含めてディレクトリを作成するdelete/deleteIfExists
ファイルを削除する。失敗したら前者は例外、後者は boolean 型で結果が返る どちらもディレクトリの中にファイルがあると削除できず、例外が発生するnewDirectoryStream(Path)
ディレクトリ内のパスをIterableの実装クラスDirectoryStream<Path>で返すlist(Path)
ディレクトリ内のファイルやディレクトリの一覧をStream<Path>で返す。引数がディレクトリでない場合は例外が発生するjava.nio.file.Files(ディレクトリの検索)
以下は全て static メソッド
walk()walkFileTree()
サブディレクトリも含めて再帰的に検索するlist()
そのディレクトリだけを検索するfind()
サブディレクトリも含めて再帰的に、条件に合致するものを検索する- これらの戻り値は全てストリームなので、パイプライン処理が可能
java.nio.file.attribute
ファイルの属性(作成時間、アクセス時間、所有者など)を表現するクラスが入ったパッケージ。属性情報のセットを示す属性ビューインターフェイスも含む
BasicFileAttributesインターフェイス
基本的な属性情報DosFileAttributesインターフェイス
DOS系の属性情報PosixFileAttributesインターフェイス
Unix/Linuxの属性情報AttributeViewインターフェイス
属性情報のセット。サブインターフェイスとして以下が存在する
BasicFileAttributeViewDosFileAttributeViewPosixFileAttributeView並列処理
並行処理ユーティリティが提供する機能
- スレッドプール
スレッドの生成と再利用- 並行コレクション
複数スレッドからの並行アクセスを適切に処理できるコレクション- アトミック変数
並行アクセスによって値の不整合を起こさないための分割不可能な一連の操作を実装(synchronized と同じ)- カウウンティング・セマフォ
有限なリソースに対して並行アクセス可能なスレッド数を自由に設定可能並列コレクション
- 並列処理に関わるAPIは以下。全て
java.util.concurrentパッケージ
BlockingQueueインターフェイスBlockingDequeインターフェイスConcurrentMapインターフェイスConcurrentHashMapクラスCopyOnWriteArrayListクラスCopyOnWriteArraySetクラス- 並列処理に対応していないコレクションオブジェクトを複数のスレッドから操作すると
java.util.ConcurrentModificationExceptionが発生する- 複数のスレッドから操作するときに拡張for文などでイテレータを使うと、イテレータを生成した時点のコレクションの中身が使用される
java.util.concurrent.ConcurrentMap インターフェイス
V getOrDefault(Object key, V defaultValue)
key に紐づく値を返す。無ければ defaultValue を返すV putIfAbsent(K key, V value)
key に紐づく値がマップにない場合のみ追加boolean remove(Object key, Object value)
key と value の両方が一致する要素があれば削除V replace(K key, V value)
key に指定した値がマップにあれば置換V replace(K key, V oldValue, V newValue)
key と oldValue の両方が一致する要素があれば値を newValue に置換// map の中身は [1, "One"], [2, "Two.2"], [3, "Three"] Map<Integer, String> map = new ConcurrentHashMap<>(); map.put(1, "One"); map.putIfAbsent(1, "One.2"); // 追加しない(KEY=1の要素が既存) map.put(2, "Two"); map.replace(2, "Two.2"); // 置換 map.replace(2, "Two.22", "Two.3"); // 置換しない(第2引数が既存の値と違う) map.put(3, "Three"); // 削除 map.remove(3, "Three2"); // 削除しない(第2引数が既存の値と違う)java.util.concurrent.CopyOnWriteArrayList クラス
- 内部で保持している要素を変更するときは、古い要素が入った配列をコピーしてそれを変更し、差し替える
そのため、リストのサイズが大きくなるとオーバーヘッドが肥大化する- 要素の変更中(新しい配列へのコピー中)に別のスレッドがリストにアクセスすると、古い配列の内容を参照することになる
java.util.concurrent.CyclicBarrier クラス
- スレッドパーティー(強調して動作するスレッドの集合)内の各スレッドの足並みを揃えるための機能を提供
- コンストラクタで協調させるスレッドの数を指定。第1引数は協調させるスレッドの数、第2引数があれば、トリップ(=バリアが解除)したときに実行される処理
new CyclicBarrier(int)new CyclicBarrier(int, Runnable)await()を実行したスレッドはCyclicBarrierのコンストラクタで指定した数のスレッドが await するまで待機する
await(long timeout)タイムアウトなしawait(long timeout, TimeUnit unit)タイムアウトあり- 4つのスレッドに対して
new CyclicBarrier(3)とすると、3つのスレッドがawaitした時点でトリップが発生する
しかし最後の1つは、さらに2つのスレッドがawaitするまでバリアを突破できないので、続きの処理は実行できない// バリアの許容数が2つに対してスレッドが3本なので、 // "wait wait wait finish finish" と出て処理が止まる ExecutorService service = Executors.newCachedThreadPool(); CyclicBarrier barrier = new CyclicBarrier(2); for (int i = 0; i < 3; i++) { service.execute(() -> { try { System.out.print("wait "); barrier.await(); System.out.println("finish "); } catch (BarrierBrokenException | InterruptedException ignore) { } }); } service.shutdown();ExecutorService の継承関係
Executor…execute(Runnabble)
ExecutorService…submit(Runnable)など
ThreadPoolExecutorForkJoinPoolScheduledExecutorService…schedule(Runnable,long,TimeUnit)等
ScheduledThreadPoolExecutorExecutorsのメソッドとそれぞれに対応するExecutorServiceのスペック
newSingleThreadExecutor()
単一のスレッドでタスクを実行newCachedThreadPool()
必要に応じて新規スレッドを生成、もしくは再利用してタスクを実行newFixedThreadPool(int)
固定数のスレッドを再利用してタスクを実行newScheduledThreadPool(int)
固定数のスレッドを再利用してタスクを実行。タスクはスケジュール可能newSingleThreadScheduledExecutor()
単一のスレッドでタスクを実行。タスクはスケジュール可能ExecutorService#execute
Executorsクラスの static メソッドで適切な性質のExecutorServiceオブジェクトを取得してexecute(Runnable)メソッドで実行- タスクの実行状態を確認するには以下のメソッドを使う
isShutdown()
true なら新規タスクは受入不可(未実行か実行中のタスクがある可能性)isTerminated()
true なら新規タスクは受入不可、かつ全てのタスクが終了した状態isShutdown()が true でなければ、新規タスクのexecuteが可能。true のときにexecuteすると例外が発生するExecutorService#submit
- ExecutorService に複数のオーバーロードメソッドがあり、戻り値は Future。メソッドによって Future から get できるものが異なる
Future<T> submit(Runnable)
タスクを実行。get できるのはタスクの成否Future<?> submit(Runnable, T)
第1引数のタスクを実行し、第2引数の値を返す。get できるのはタスクの成否Future<T> submit(Callable<T>)
タスクを実行。get できるのはタスクからの戻り値- タスクはすぐ実行されるが、
Future#get()を実行するとタスクが終了した後も値が取得できるまで待機時間が発生するFuture<T>からはsubmitしたタスクのキャンセルもできる(可能な場合のみ)Runnable と Callable
Runnable
- 戻り値を返さない
- チェック例外をスローできない
executeでもsubmitでも実行できるCallable
- 戻り値を返すことができる
- チェック例外をスローできる
submitでしか実行できないjava.util.concurrent.Future インターフェイス
V get()
タスクの実行結果を取得できるboolean cancel(boolean)
タスクのキャンセルを試みるboolean isCancelled()
タスクがキャンセルされたかを知るboolean isDone()
タスクが完了しているかどうかを知るパラレルストリーム
- 生成
Collection#parallelStream()
コレクションからパラレルストリームを生成- 相互変換
BaseStream#parallel()
シーケンシャルストリームからパラレルストリームを生成BaseStream#sequential()
パラレルストリームからシーケンシャルストリームを生成- 判定
BaseStream#isParallel()
自身がパラレルストリームかどうかを判定// パラレルストリームの生成 Arrays.asList(1, 2, 3).parallelStream().forEach(System.out::println); // シーケンシャルストリームからパラレルストリームを生成 Stream.of("a", "b", "c").parallel().forEach(System.out::println); // パラレルストリームからシーケンシャルストリームを生成 Arrays.asList("A", "B", "C").parallelStream().sequential().forEach(System.out::println);Fork/Joinフレームワーク
※ 私はここを捨てました。真面目な方はちゃんと勉強しましょう
アトミック変数
- Atomic〜 で始まる名前のクラスは、自身が扱う値への操作がスレッドセーフになることを保証する
- 主なクラスは以下。Float や Double は存在しない
AtomicInteger… int型AtomicLong… long型AtomicBoolean… boolean型AtomicReference… 参照型JDBC
クエリの実行
- 使用するクラスが所属するパッケージは
java.sqlとjavax.sql- JDBC で DB に接続するための URL フォーマットは以下の通り
jdbc:[DB名]//[host(:port)]/[db-name](?option)- 基本的な処理の流れは以下の通り
DriverManager#getConnection(url,id,pass)でConnection取得Connection#createStatement()でStatement取得Statement#executeQuery(sql)でResultSet取得ResultSetからクエリの結果を取り出す- JDBC3.0 以前では
DriverManager#getConnectionの前にClass.forName([JDBCドライバクラス名])を実行する必要があったexecuteQueryで実行するクエリの結果が0件でも戻り値は null ではなく、空のResultSetになる- 1つの
Statementで扱えるResultSetは1つだけ。最初のResultSetを閉じずに別のResultSetを取得すると、最初のは自動的に閉じられる。閉じられたResultSetを操作しようとすると例外
executeUpdateなどを実行したときも自動で閉じるStatementにあるメソッドの使い分け
ResultSet executeQuery(String sql)
クエリの実行結果を返すint executeUpdate(String sql)
INSERT/UPDATE/DELETEなどのSQLを実行し、処理件数を返すboolean execute(String sql)
クエリを含む、あらゆる種類の SQL を実行して処理の結果としてResultSetが得られたかを返す。true ならResultSetが返ってきており、false ならそうではない
処理の結果ResultSetが返ってきたならStatement#getResultSet()で取得する。ResultSetでなければStatement#getUpdateCount()で処理件数を取得するResultSet の取得と性質
Connection#createStatement(type, concurrency)でResultSetの「スクロール可否」と「テーブルデータの更新可否」を順番に指定する- スクロール可否は以下の3種類で、全て
ResultSetクラスの定数
TYPE_FORWARD_ONLY… 順方向にのみ移動可TYPE_SCROLL_INSENSITIVE… 双方向に移動可。カーソルへの変更は反映しないTYPE_SCROLL_SENSITIVE… 双方向に移動可。カーソルへの変更を反映する- テーブルデータの更新可否は以下の2種類で、全て
ResultSetクラスの定数
CONCUR_READ_ONLY… 読み込みのみCONCUR_UPDATABLE… 更新可能Statement#createStatement(..., ResultSet.CONCUR_UPDATABLE)で更新可能なResultSetを取得する時、更新対象とするカラムをexecuteQueryの select 文に指定しておかなくてはならないResultSet のスクロール用メソッド
boolean absolute(int)
指定した行(絶対位置を指定)へ移動。先頭行は1。0はbeforeFirstboolean relative(int)
相対位置を指定して移動。正の値なら次の行へ、負の値なら前の行にゆくboolean next()
ひとつ次の行に移動boolean previous()
ひとつ前の行に移動boolean first()
先頭行に移動void beforeFirst()
先頭行の直前に移動boolean last()
最終行に移動void afterLast()
最終行の直後に移動更新可能な ResultSet
- 更新
updateStringやupdateIntで変更しupdateRowで変更を確定させる
StatementのタイプがTYPE_SCROLL_INSENSITIVEでもupdateRowしない限り、DB の中身どころか結果セットさえ変更されない
updateString(int, String)updateInt(int, int)updateRow()- 挿入
moveToInsertRowで挿入行に移動しupdateStringやupdateIntで挿入内容を指定してinsertRowで挿入する
moveToInsertRow()insertRow()- 削除
現在行を削除する
deleteRow()ローカライズとフォーマット
java.util.Locale オブジェクトの取得
Locale#getDefault()
Java実行環境のロケールnew Locale(String)
引数は「言語コード」new Loacle(String, String)
引数は「言語コード, 国コード」new Loacle(String, String, String)
引数は「言語コード, 国コード, バリアント」- new で生成した
Locale.Builderに適切な値を設定してbuild()で生成java.util.Properties
- サポートするファイルフォーマットはテキストとXML
- テキストファイルの場合、キーと値を = もしくは : で区切って列挙する
- ファイルからプロパティリストをロード
load(InputStream)load(Reader)loadFromXML(InputStream)- プロパティリストを出力
list(OutputStream)list(Writer)entrySet()forEach(BiConsumer)- プロパティの取得
getProperty(String)
該当するKeyが無ければ null を返すgetProperty(String, String)
該当するKeyが無ければ第2引数を返すjava.util.ListResourceBundle
- リソースを .class ファイルで用意してクラスパスが張られている場所に置く
- 使い方は以下の通り
ListResourceBundleを継承した public クラスを定義
public Object[][] getContents()をオーバーライド
このクラスの完全修飾名(パッケージ名+クラス名)が基底名に、このクラスがデフォルトロケール用になる
例:クラス名は "MyResource" とする- 1とは異なるロケール用のクラスを
ListResourceBundleを継承して定義する
ネーミングルールは 「基底名言語コード国コード」
例:英語ロケール用のクラス名は "MyResource_en_US" となるResourceBundle#getBundle(基底名[, ロケール])でListResourceBundleオブジェクトを取得ResourceBundle#getXXXXX(キー文字列)で値を取り出すjava.util.PropertyResourceBundle
- リソースを .properties ファイルで用意してクラスパスが張られている場所に置く
- 使い方は以下の通り
- デフォルトロケール用のプロパティファイルを作成
- 拡張子は .properties
- 『キー名 = 値』のフォーマットで複数のプロパティを定義
- ファイルは ISO-8859-1 エンコードされている必要がある
- ファイルの命名規則は
ListResourceBundleのクラス名と同じ- 1とは異なるロケール用のファイルを作成
- ファイルの命名規則は
ListResourceBundleのクラス名と同じ- 英語ロケール用なら MyResource_en_US.properties となる
ResourceBundle#getBundle(基底名[, ロケール])でPropertyResourceBundleオブジェクトを取得
ListResourceBundleを取得するのと同じメソッド- 以下のメソッドで値を取り出す。getInt はない
ResourceBundle#getObject(キー文字列)ResourceBundle#getString(キー文字列)ResourceBundle#getStringArray(キー文字列)使用されるリソースバンドルの優先順位
- ロケールに対応するリソースバンドルが存在しなければ
MissingResourceException例外が発生する- 同名のリソースバンドルが複数あっても例外にはならない
- ファイル単位ではなく個々のプロパティ単位でリソースバンドルが検索される。検索の優先順位は以下の通り
- 言語コード、国コードが一致
- 言語コードが一致
- デフォルトロケールが一致
- 指定したキーに対応するプロパティがどのクラス/ファイルにも存在しなければ
MissingResourceExceptionが発生するListResourceBundleクラスとプロパティファイルの両方が同じ名前で存在すると、ファイルよりクラスのほうが優先されるNumberFormatを使って数値をフォーマット
NumberFormatクラスの static メソッドを使って目的に応じたオブジェクトを取得
getInstance()
デフォルトロケールの数値フォーマットgetInstance(Locale)
任意のロケールの数値フォーマットgetCurrencyInstance(Locale)
任意のロケールの通貨フォーマットgetIntegerInstance(Locale)
任意のロケールの整数フォーマットformat(long)もしくはformat(double)でフォーマット済み文字列を取得parse(String)で文字列から数値を取得。戻り値はNumber更新履歴
- 2020/08/23
Qiita に公開- 2020/08/24
関数型インターフェイスの一覧を表形式に変更
列挙値に関するサンプルコードを追加
- 投稿日:2020-08-23T17:36:52+09:00
SpringSecurity TextEncryptor: 共通鍵暗号化・復号
はじめに
暗号化、復号はよく使う処理であり、SpringSecurityでは便利なインターフェイスが用意されており、簡単に使えますので、サンプルを作成してみます。
暗号化、復号インターフェス
テキスト用:org.springframework.security.crypto.encrypt.TextEncryptor
バイト配列用:org.springframework.security.crypto.encrypt.BytesEncryptor乱数生成インターフェス
テキスト用:org.springframework.security.crypto.keygen.StringKeyGenerator
バイト配列用:org.springframework.security.crypto.keygen.BytesKeyGeneratorサンプル
package sample.security; import java.util.Base64; import org.apache.commons.codec.binary.Hex; import org.springframework.security.crypto.encrypt.BytesEncryptor; import org.springframework.security.crypto.encrypt.Encryptors; import org.springframework.security.crypto.encrypt.TextEncryptor; import org.springframework.security.crypto.keygen.KeyGenerators; public class Test { public static void main(String[] args) { // 平文 String orginalText = "私は◯◯が好きです。"; // 共通鍵 String encryptSecrerKey = "GOV2dkHGQcE1ZcX8"; // Salt:乱数生成 byte[] bytes = KeyGenerators.secureRandom(16).generateKey(); String salt = new String(Hex.encodeHexString(bytes)); // CBC方式 TextEncryptor cbcTextEncryptor = Encryptors.text(orginalText, salt); // 暗号化 String encryptedCbcData = cbcTextEncryptor.encrypt(orginalText); System.out.println("暗号化した結果(AES-CBC): " + encryptedCbcData); // 復号 String decryptedCbcData = cbcTextEncryptor.decrypt(encryptedCbcData); System.out.println("復号した結果(AES-CBC): " + decryptedCbcData); // GCM方式 TextEncryptor aesGcmTextEncryptor = Encryptors.delux(encryptSecrerKey, salt); // 暗号化 String encryptedData = aesGcmTextEncryptor.encrypt(orginalText); System.out.println("暗号化した結果(AES-GCM): " + encryptedData); // 復号 String decryptedData = aesGcmTextEncryptor.decrypt(encryptedData); System.out.println("復号した結果(AES-GCM): " + decryptedData); // バイナリ(CBC) BytesEncryptor binaryEncryptor = Encryptors.standard(encryptSecrerKey, salt); // 暗号化 String encryptedBinaryData = Base64.getEncoder() .encodeToString(binaryEncryptor.encrypt(orginalText.getBytes())); System.out.println("暗号化した結果(バイナリCBC): " + encryptedBinaryData); // 復号 byte[] decryptedBinaryData = binaryEncryptor.decrypt(Base64.getDecoder().decode(encryptedBinaryData)); System.out.println("復号した結果(バイナリCBC): " + new String(decryptedBinaryData)); // バイナリ(GCM) BytesEncryptor aesGcmBinaryEncryptor = Encryptors.stronger(encryptSecrerKey, salt); // 暗号化 String gcmEncryptedBinaryData = Base64.getEncoder() .encodeToString(aesGcmBinaryEncryptor.encrypt(orginalText.getBytes())); System.out.println("暗号化した結果(バイナリGCM): " + gcmEncryptedBinaryData); // 復号 byte[] gcmDecryptedBinaryData = binaryEncryptor.decrypt(Base64.getDecoder().decode(encryptedBinaryData)); System.out.println("復号した結果(バイナリGCM): " + new String(gcmDecryptedBinaryData)); } }実行結果例:
暗号化した結果(AES-CBC): a34e20774314b85322de3eaf6c10f6990befe353d382cc449039524ffb7042b442f2a7a00beeddc94c8ad1495f6a0fba
復号した結果(AES-CBC): 私は◯◯が好きです。
暗号化した結果(AES-GCM): 1f5c89aeabf9f05a3cb286d1eca6e06ecd3259e9e52cea96d80e41d60614e436657317b7e69ad5b3e8672adaadd2434af69cbd36b516462908bef26d1ecf
復号した結果(AES-GCM): 私は◯◯が好きです。
暗号化した結果(バイナリCBC): zQg1LujXz6lpMwVoqNvG+ETtDbEC/LE0kq1LKJ+4d8ntbPDHDsAC0e5w6Eym7Hps
復号した結果(バイナリCBC): 私は◯◯が好きです。
暗号化した結果(バイナリGCM): gSFtQJCV0OSkjdg8sf+WHxYAFIdZrgb6MFWsPTmzau67lzFVW+ZJP36bWPQQ0p8/QZ9FIgQ7isZm4fIYt1g=
復号した結果(バイナリGCM): 私は◯◯が好きです。以上
- 投稿日:2020-08-23T13:32:05+09:00
Java + Oracle Database 12c で主要な SQL 型の値を取得するサンプルコード
概要
- Oracle Database 12c にてテーブルに主要な SQL データ型のカラムを定義して、Java のプログラムからカラムの値を取得するサンプルコードを示す
- 今回の動作確認環境: Oracle Database 12c Release 2 (12.2.0.1.0) Enterprise Edition (on Docker) + Oracle JDBC Thin driver (ojdbc8.jar) 19.7.0.0 + Java 14 (AdoptOpenJDK 14.0.2) + Gradle 6.6 + macOS Catalina
サンプルコード
ファイル一覧
├── build.gradle └── src └── main └── java └── JdbcSample.javabuild.gradle
plugins { id 'application' id 'java' } sourceCompatibility = JavaVersion.VERSION_14 repositories { mavenCentral() } dependencies { // 実行時に Oracle JDBC Driver を使うだけなら runtimeOnly を指定 //runtimeOnly 'com.oracle.database.jdbc:ojdbc8:19.7.0.0' // 今回は oracle.jdbc.OracleTypes を使うため implementation を指定 implementation 'com.oracle.database.jdbc:ojdbc8:19.7.0.0' } tasks.withType(JavaCompile) { // Java 14 のプレビュー機能を使う options.compilerArgs += ['--enable-preview'] } application { // Java 14 のプレビュー機能を使う applicationDefaultJvmArgs = ['--enable-preview'] mainClassName = 'JdbcSample' }JdbcSample.java
import oracle.jdbc.OracleTypes; // 普通に使うだけなら不要 (今回は Oracle 拡張 JDBC 型の情報を取得するために使用) import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.Statement; import java.sql.Types; import java.util.Arrays; class JdbcSample { public static void main(String[] args) throws Exception { // MySQL に接続 String url = "jdbc:oracle:thin:@//localhost:1521/testdb"; String user = "javarista"; String password = "cafebabe"; Connection con = DriverManager.getConnection(url, user, password); Statement stmt = con.createStatement(); // テーブルを作成 // いろいろな SQL データ型でカラムを定義 // (Java 14 プレビュー機能で使えるヒアドキュメントっぽく書けるテキストブロック機能を使う) stmt.execute(""" create table test ( -- 文字列型 my_char CHAR(8 CHAR), -- 固定長文字列 (基本は最大長 2000 bytes) my_varchar2 VARCHAR2(512 CHAR), -- 可変長文字列 (基本は最大長 4000 bytes) my_clob CLOB, -- Character Large Object -- バイナリ型 my_raw RAW(256), -- 可変長バイナリ (基本は最大長 2000 bytes) my_blob BLOB, -- Binary Large Object -- 真偽値型 my_number_1 NUMBER(1), -- 0 は false、それ以外の値は true として解釈される -- 整数型 my_number_38 NUMBER(38), -- 最大38桁 my_smallint SMALLINT, -- Oracle データ型に変換される ANSI データ型 my_integer INTEGER, -- Oracle データ型に変換される ANSI データ型 -- 浮動小数点型 my_binary_float BINARY_FLOAT, -- 単精度浮動小数点数 4 bytes my_binary_double BINARY_DOUBLE, -- 倍精度浮動小数点数 8 bytes my_float FLOAT, -- Oracle データ型 FLOAT(126) に変換される ANSI データ型 my_double_precision DOUBLE PRECISION, -- Oracle データ型 FLOAT(126) に変換される ANSI データ型 my_real REAL, -- Oracle データ型 FLOAT(63) に変換される ANSI データ型 -- 固定小数点型 my_fixed_point_number NUMBER(7, 4), -- 固定小数点数 my_numeric NUMERIC(7, 4), -- Oracle データ型に変換される ANSI データ型 my_decimal DECIMAL(7, 4), -- Oracle データ型に変換される ANSI データ型 -- 時間型 my_date DATE, -- 年月日 + 時分秒 my_timestamp TIMESTAMP(9), -- 年月日 + 時分秒 + ナノ秒 my_timestamp_with_time_zone TIMESTAMP(9) WITH TIME ZONE -- 年月日 + 時分秒 + ナノ秒 + タイムゾーン )"""); // レコードを追加 // (Java 14 プレビュー機能で使えるヒアドキュメントっぽく書けるテキストブロック機能を使う) stmt.execute(""" insert into test values ( -- 文字列型 'Hello', -- CHAR 'Hello', -- VARCHAR2 'Hello', -- CLOB -- バイナリ型 HEXTORAW('CAFEBABE'), -- RAW HEXTORAW('CAFEBABE'), -- BLOB, -- 真偽値型 1, -- 0 は false、それ以外の値は true として解釈される -- 整数型 12345678901234567890123456789012345678, -- NUMBER(38) 32767, -- SMALLINT 2147483647, -- INTEGER -- 浮動小数点型 123.0001, -- BINARY_FLOAT 123.0001, -- BINARY_DOUBLE 123.0001, -- FLOAT 123.0001, -- DOUBLE PRECISION 123.0001, -- REAL -- 固定小数点型 123.0001, -- NUMBER(7, 4) 123.0001, -- NUMERIC(7, 4) 123.0001, -- DECIMAL(7, 4) -- 時間型 TO_DATE('2001-02-03 04:05:06', 'YYYY-MM-DD HH24:MI:SS'), -- DATE TO_TIMESTAMP('2001-02-03 04:05:06.999999999', 'YYYY-MM-DD HH24:MI:SS.FF9'), -- TIMESTAMP(9) TO_TIMESTAMP_TZ('2001-02-03 04:05:06.999999999 +00:00', 'YYYY-MM-DD HH24:MI:SS.FF9 TZH:TZM') -- TIMESTAMP(9) WITH TIME ZONE )"""); // レコードを取得 ResultSet rs = stmt.executeQuery("select * from test"); while (rs.next()) { // カラムの JDBC 型や SQL 型に対する Java オブジェクトの型を取得 System.out.println("カラム名 - JDBC 型 - データベース固有の SQL 型 - Java オブジェクトの型"); ResultSetMetaData rsmd = rs.getMetaData(); for (int i = 1; i <= rsmd.getColumnCount(); i++) { System.out.println( rsmd.getColumnName(i) + " - " + getJdbcTypeName(rsmd.getColumnType(i)) + " - " + rsmd.getColumnTypeName(i) + " - " + rsmd.getColumnClassName(i)); } System.out.println(); // カラムの値を取得していく System.out.println("カラム名 - カラムの値"); // 文字列型 System.out.println("my_char=" + rs.getString("my_char")); System.out.println("my_varchar2=" + rs.getString("my_varchar2")); System.out.println("my_clob=" + rs.getClob("my_clob")); // バイナリ型 System.out.println("my_raw=" + Arrays.toString(rs.getBytes("my_raw"))); System.out.println("my_blob=" + rs.getBlob("my_blob")); // 真偽値型 System.out.println("my_number_1=" + rs.getBoolean("my_number_1")); // 整数型 System.out.println("my_number_38=" + rs.getBigDecimal("my_number_38")); System.out.println("my_smallint=" + rs.getInt("my_smallint")); System.out.println("my_integer=" + rs.getInt("my_integer")); // 浮動小数点型 System.out.println("my_binary_float=" + rs.getFloat("my_binary_float")); System.out.println("my_binary_double=" + rs.getDouble("my_binary_double")); System.out.println("my_float=" + rs.getDouble("my_float")); System.out.println("my_double_precision=" + rs.getDouble("my_double_precision")); System.out.println("my_real=" + rs.getDouble("my_real")); // 固定小数点型 System.out.println("my_fixed_point_number=" + rs.getBigDecimal("my_fixed_point_number")); System.out.println("my_numeric=" + rs.getBigDecimal("my_numeric")); System.out.println("my_decimal=" + rs.getBigDecimal("my_decimal")); // 時間型 System.out.println("my_date=" + rs.getTimestamp("my_date")); System.out.println("my_timestamp=" + rs.getTimestamp("my_timestamp").toInstant()); System.out.println("my_timestamp_with_time_zone=" + rs.getTimestamp("my_timestamp_with_time_zone").toInstant()); } stmt.close(); con.close(); } // JDBC 型の名称を取得する private static String getJdbcTypeName(int type) throws IllegalAccessException { // Java 標準の JDBC 型から探す Field[] fs = Types.class.getDeclaredFields(); for (Field f : fs) { if (type == f.getInt(null)) { return f.getName(); } } // Oracle 拡張機能の JDBC 型から探す fs = OracleTypes.class.getDeclaredFields(); for (Field f : fs) { if (type == f.getInt(null)) { return "OracleTypes." + f.getName(); } } // 合致する JDBC 型が無かったので type 値を文字列化して返す return "" + type; } }実行結果
Gradle の run タスクで実行。
$ gradle run Starting a Gradle Daemon (subsequent builds will be faster) > Task :compileJava 注意:/Users/foo/bar/src/main/java/JdbcSample.javaはプレビュー言語機能を使用します。 注意:詳細は、-Xlint:previewオプションを指定して再コンパイルしてください。 > Task :run カラム名 - JDBC 型 - データベース固有の SQL 型 - Java オブジェクトの型 MY_CHAR - CHAR - CHAR - java.lang.String MY_VARCHAR2 - VARCHAR - VARCHAR2 - java.lang.String MY_CLOB - CLOB - CLOB - oracle.jdbc.OracleClob MY_RAW - VARBINARY - RAW - [B MY_BLOB - BLOB - BLOB - oracle.jdbc.OracleBlob MY_NUMBER_1 - NUMERIC - NUMBER - java.math.BigDecimal MY_NUMBER_38 - NUMERIC - NUMBER - java.math.BigDecimal MY_SMALLINT - NUMERIC - NUMBER - java.math.BigDecimal MY_INTEGER - NUMERIC - NUMBER - java.math.BigDecimal MY_BINARY_FLOAT - OracleTypes.BINARY_FLOAT - BINARY_FLOAT - java.lang.Float MY_BINARY_DOUBLE - OracleTypes.BINARY_DOUBLE - BINARY_DOUBLE - java.lang.Double MY_FLOAT - NUMERIC - NUMBER - java.lang.Double MY_DOUBLE_PRECISION - NUMERIC - NUMBER - java.lang.Double MY_REAL - NUMERIC - NUMBER - java.lang.Double MY_FIXED_POINT_NUMBER - NUMERIC - NUMBER - java.math.BigDecimal MY_NUMERIC - NUMERIC - NUMBER - java.math.BigDecimal MY_DECIMAL - NUMERIC - NUMBER - java.math.BigDecimal MY_DATE - TIMESTAMP - DATE - java.sql.Timestamp MY_TIMESTAMP - TIMESTAMP - TIMESTAMP - oracle.sql.TIMESTAMP MY_TIMESTAMP_WITH_TIME_ZONE - OracleTypes.TIMESTAMPTZ - TIMESTAMP WITH TIME ZONE - oracle.sql.TIMESTAMPTZ カラム名 - カラムの値 my_char=Hello my_varchar2=Hello my_clob=oracle.sql.CLOB@7c711375 my_raw=[-54, -2, -70, -66] my_blob=oracle.sql.BLOB@3a44431a my_number_1=true my_number_38=12345678901234567890123456789012345678 my_smallint=32767 my_integer=2147483647 my_binary_float=123.0001 my_binary_double=123.0001 my_float=123.0001 my_double_precision=123.0001 my_real=123.0001 my_fixed_point_number=123.0001 my_numeric=123.0001 my_decimal=123.0001 my_date=2001-02-03 04:05:06.0 my_timestamp=2001-02-02T19:05:06.999999999Z my_timestamp_with_time_zone=2001-02-03T04:05:06.999999999Z BUILD SUCCESSFUL in 16s 2 actionable tasks: 2 executedOracle Database の真偽値型
Oracle Database JDBC開発者ガイド, 12cリリース2 (12.2) - Oracleデータへのアクセスと操作
BOOLEANデータベース型が存在しないため、getBooleanを使用すると必ずデータ型変換が実行されます。getBooleanメソッドは数値用の列に対してのみサポートされます。このような列に対してgetBooleanが適用されると、0(ゼロ)値はfalseとして、それ以外の値はtrueとして解釈されます。別の種類の列に適用された場合は、getBooleanは例外java.lang.NumberFormatExceptionを戻します。
参考資料
- JDBC API 入門 - SQL と Java の型のマッピング
- java.sql (Java SE 14 & JDK 14)
- Oracle Database概要, 12cリリース2 (12.2) - 表と表クラスタ - Oracleデータ型
- Oracle Database SQL言語リファレンス, 12cリリース2 (12.2) - データ型
- Oracle Database SQL言語リファレンス, 12cリリース2 (12.2) - 日時書式モデル
- Oracle Database JDBC開発者ガイド, 12cリリース2 (12.2) - Oracleデータへのアクセスと操作 - SQL型とJava型間のデフォルト・マッピング
- Oracle JDBC Frequently Asked Questions - What are the Oracle JDBC releases Vs JDK versions?
- Maven Central Developers Guide
- Java + H2 Database で主要な JDBC 型の値を取得するサンプルコード - Qiita
- Oracle Database 12c を macOS 上の Docker で構築する - Qiita
- 投稿日:2020-08-23T00:24:57+09:00
Javaことはじめ
Eclipseショートカットキー
■ 補完(Ctrl + Space)
(sysout) System.out.println();
(syso) System.out.println();
(main) public static void main(String[] args) {}■ ローカル変数を宣言(Ctrl + 2 → L)
new ArrayList(); → ArrayList arrayList = new ArrayList();■ その他のショートカット
ソースコードのフォーマット(Ctrl + Shift + F)
コメントアウト(Ctrl + /)
クイックフィックス(Ctrl + 1)
1行移動、1行コピー(Alt + ↓↑、Ctrl + Alt + ↓↑)
1行削除(Ctrl + D)
メソッドの抽出(Alt + Shift + M)
呼び出し階層を開く(Ctrl + Alt + H)
宣言を開く(Ctrl + クリック)
型を開く(Ctrl + Shift + T)プログラムの書き方
スッキリわかるJava入門を読んだ自分用のまとめ
▼クラスブロック+メインブロック
Main.javapublic class Main { public static void main(String[] args) { } }メインブロック内の記述
Main.javaSystem.out.println("こんにちは");「こんにちは」と表示させる System.out.println("二重引用符(¥")");「二重引用符(")」と表示させる int age;//変数宣言(ageという箱を用意) age = 20;//変数age 代入 20 int age = 20;//変数 ageを20で初期化 age = 32;//変数ageに再代入 final double Pi = 3.14;//定数として円周率を宣言 //:データ型(整数) byte glasses = 2;//所持するメガネの数 short age = 20;//年齢 int salary = 180000;//給与金額 long worldPeople = 6900000000L;//世界の人口 //データ型(少数) float weight = 56;//体重 double pi = 3.14;//円周率 //データ型(真偽値) boolean isError = true;//trueかfalse //データ型(文字、文字列) char initial = F;//イニシャル1文字 String name = Haru;//名前 int m = Math.max(①,②);//数字を比較して大きい方を代入 int n = Interger.parseInt(①);文字列を数字に変換 int r = new java.util.Random().nextInt(①);//乱数を発生(最大①まで) String s = new java.util.Scanner(System.in).nextLine();キーボードから文字入力 int i = new java.util.Scanner(System.in).nextInt();キーボードから整数入力分岐
Main.java//if if (tenki == true) { System.out.println("晴れです"); }else { System.out.println("雨です"); } //switch int lucky = new java.util.Random().nextInt(3)+1; System.out.println(lucky); switch (lucky) { case 1: System.out.println("大吉です"); break; case 2: System.out.println("吉です"); break; case 3: System.out.println("凶です"); } //繰り返し処理の中断 break文 //今回だけ中断して次の周へ continue文 //論理演算子 &&(かつ)、||(または)繰り返し
Main.javafor (int i = 0; i < 10; i++) { } do { if (i % 3 == 0) { System.out.println(i); } i++; } while (i < 100);配列
Main.javaint[] score;//int型の要素を代入できる配列変数scoreを用意 score = new int[5];int型の要素を5つ作成してscoreに代入 score.length//配列の要素数の取得 int[] scores1 = new int[] {1,2,3};//省略法1 int[] scores2 = {1,2,3};//省略法2 for (要素の型 変数名:配列変数名){//拡張for文 } //例 int[] moneyList = {1,2,3}; for(int i=0; i < moneyList.length; i++) { System.out.println(moneyList[i]); } for(int m : moneyList) { System.out.println(m); }メソッド
Main.javapublic static void hello() {//helloメソッド System.out.println("こんにちは"); } hello();//helloメソッドを呼び出す //例 public static void main(String[] args) { introduceOneself(); } public static void introduceOneself() { String name = "はる"; int age = 6; double height = 110.5; char zodiac = '午'; System.out.println(name); System.out.println(age); System.out.println(height); System.out.println(zodiac); } //例(オーバーロード) public static void main(String[] args) { String address = "hoge@hogehoho.hoge"; String text = "メールの本文"; email(address,text); } public static void email(String address, String text) { System.out.println(address + "に、以下のメールを送りました"); System.out.println("件名:無題"); System.out.println("本文:" + text); } public static void email(String title, String address, String text) { System.out.println(address + "に、以下のメールを送りました"); System.out.println("件名:" + title); System.out.println("本文:" + text); } //例(三角形の面積) public static void main(String[] args) { double triangleArea = calcTriangleArea(10.0,5.0); System.out.println(triangleArea); } public static double calcTriangleArea(double bottom, double height) { double area = bottom * height / 2; return area; }
- 投稿日:2020-08-23T00:24:57+09:00
今日から携わるJava
Javaを勉強して必要なことのまとめ
Eclipseショートカットキー
■ 補完(Ctrl + Space)
(sysout) System.out.println();
(syso) System.out.println();
(main) public static void main(String[] args) {}■ ローカル変数を宣言(Ctrl + 2 → L)
new ArrayList(); → ArrayList arrayList = new ArrayList();■ その他のショートカット
ソースコードのフォーマット(Ctrl + Shift + F)
コメントアウト(Ctrl + /)
クイックフィックス(Ctrl + 1)
1行移動、1行コピー(Alt + ↓↑、Ctrl + Alt + ↓↑)
1行削除(Ctrl + D)
メソッドの抽出(Alt + Shift + M)
呼び出し階層を開く(Ctrl + Alt + H)
宣言を開く(Ctrl + クリック)
型を開く(Ctrl + Shift + T)プログラムの書き方
スッキリわかるJava入門を読んだ自分用のまとめ
https://sukkiri.jp/books/sukkiri_java3▼クラスブロック+メインブロック
Main.javapublic class Main { public static void main(String[] args) { } }メインブロック内の記述
Main.javaSystem.out.println("こんにちは");「こんにちは」と表示させる System.out.println("二重引用符(¥")");「二重引用符(")」と表示させる int age;//変数宣言(ageという箱を用意) age = 20;//変数age 代入 20 int age = 20;//変数 ageを20で初期化 age = 32;//変数ageに再代入 final double Pi = 3.14;//定数として円周率を宣言 //:データ型(整数) byte glasses = 2;//所持するメガネの数 short age = 20;//年齢 int salary = 180000;//給与金額 long worldPeople = 6900000000L;//世界の人口 //データ型(少数) float weight = 56;//体重 double pi = 3.14;//円周率 //データ型(真偽値) boolean isError = true;//trueかfalse //データ型(文字、文字列) char initial = F;//イニシャル1文字 String name = Haru;//名前 int m = Math.max(①,②);//数字を比較して大きい方を代入 int n = Interger.parseInt(①);文字列を数字に変換 int r = new java.util.Random().nextInt(①);//乱数を発生(最大①まで) String s = new java.util.Scanner(System.in).nextLine();キーボードから文字入力 int i = new java.util.Scanner(System.in).nextInt();キーボードから整数入力分岐
Main.java//if if (tenki == true) { System.out.println("晴れです"); }else { System.out.println("雨です"); } //switch int lucky = new java.util.Random().nextInt(3)+1; System.out.println(lucky); switch (lucky) { case 1: System.out.println("大吉です"); break; case 2: System.out.println("吉です"); break; case 3: System.out.println("凶です"); } //繰り返し処理の中断 break文 //今回だけ中断して次の周へ continue文 //論理演算子 &&(かつ)、||(または)繰り返し
Main.javafor (int i = 0; i < 10; i++) { ブロック } while (i < 100) { ブロック } do { if (i % 3 == 0) { System.out.println(i); } i++; } while (i < 100);配列
Main.javaint[] score;//int型の要素を代入できる配列変数scoreを用意 score = new int[5];int型の要素を5つ作成してscoreに代入 score.length//配列の要素数の取得 int[] scores1 = new int[] {1,2,3};//省略法1 int[] scores2 = {1,2,3};//省略法2 for (要素の型 変数名:配列変数名){//拡張for文 } //例 int[] moneyList = {1,2,3}; for(int i=0; i < moneyList.length; i++) { System.out.println(moneyList[i]); } for(int m : moneyList) { System.out.println(m); }メソッド
Main.java//メソッドの定義 public static 戻り値の型 メソッド名(引数リスト) { メソッドが呼び出されたときに実行される具体的な処理 } public static void hello() {//helloメソッド、voidは戻り値がなしのときに使用 System.out.println("こんにちは"); } hello();//helloメソッドを呼び出す //例 public static void main(String[] args) { introduceOneself(); } public static void introduceOneself() { String name = "はる"; int age = 6; double height = 110.5; char zodiac = '午'; System.out.println(name); System.out.println(age); System.out.println(height); System.out.println(zodiac); } //例(オーバーロード) public static void main(String[] args) { String address = "hoge@hogehoho.hoge"; String text = "メールの本文"; email(address,text); } public static void email(String address, String text) { System.out.println(address + "に、以下のメールを送りました"); System.out.println("件名:無題"); System.out.println("本文:" + text); } public static void email(String title, String address, String text) { System.out.println(address + "に、以下のメールを送りました"); System.out.println("件名:" + title); System.out.println("本文:" + text); } //例(三角形の面積) public static void main(String[] args) { double triangleArea = calcTriangleArea(10.0,5.0); System.out.println(triangleArea); } public static double calcTriangleArea(double bottom, double height) { double area = bottom * height / 2; return area; }▼参考:メソッドの使い方
https://www.javadrive.jp/start/method/index1.html複数クラスを用いた開発
Calc.javapublic class Calc { public static void main(String[] args) { int a = 10; int b = 2; int total = CalcLogic.tasu(a, b); int delta = CalcLogic.hiku(a, b); System.out.println("足すと" + total + "、引くと" + delta); } }CalcLogic.javapublic class CalcLogic { public static void main(String[] args) { public static int tasu(int a, int b) { return (a + b); } public static int hiku(int a, int b) { return (a - b); } } }インスタンスとクラス
オブジェクト指向
Main.javapublic class Main { public static void main(String[] args) { Cleric c = new Cleric(); c.name = "聖職者"; c.SelfAid(); c.pray(3); } }Cleric.javaimport java.util.Random; public class Cleric { String name; int hp = 50; final int MAX_HP = 50; int mp = 10; final int MAX_MP = 10; public void SelfAid() { System.out.println(this.name + "は、セルフエイドを唱えた"); this.hp = this.MAX_HP; this.mp -= 5; System.out.println("HPが最大まで回復した"); } public int pray(int sec) { System.out.println(this.name + "は" + sec + "秒間天に祈った!"); int recover = new Random().nextInt(3) + sec; int recoverActual = Math.min(this.MAX_MP - this.mp, recover); this.mp += recoverActual; System.out.println("MPが回復した" + recoverActual); return recoverActual; } }様々なクラス機構
コンストラクタの条件
・メソッド名がクラス名と完全に等しい
・メソッド宣言に戻り値が記述されていない(voidもダメ)public class クラス名 { クラス名() { 自動的に実行する処理 } }コンストラクタの特例
クラスに1つもコンストラクタが定義されていない場合に限って、「引数なし、処理内容なし」のコンストラクタがコンパイル時に自動的に追加されるThief.javapublic class Thief { String name; int hp; int mp; //new Thief("ハルタ", 40, 5)でインスタンス化する場合の記述 public Thief(String name, int hp, int mp) { this.name = name; this.hp = hp; this.mp = mp; } //new Thief("ハルタ", 40)でインスタンス化する場合の記述(MPは5で初期化) public Thief(String name, int hp) { this(name, hp, 5); } //new Thief("ハルタ")でインスタンス化する場合の記述(HPは40,MPは5で初期化) public Thief(String name) { this(name, 40); } //new Thief()ではインスタンス化できないようにする(名前の無いThiefは存在させない) }上記のThiefクラスを利用したプログラム
Main.javapublic class Main { public static void heal(int hp) { hp += 10; } public static void heal(Thief thief) { thief.hp += 10; } public static void main(String[] args) { int baseHp = 25; Thief t = new Thief("ハルタ", baseHp); System.out.println(baseHp + ":" + t.hp); heal(baseHp); heal(t); System.out.println(baseHp + ":" + t.hp); } //実行結果 // 25:25(引数がint型の場合、変数baseHpの値が引数hpにコピーされる値渡しのため) // 25:35(引数がクラス型の場合、変数tが示すアドレスが引数thiefにコピーされる参照渡しにより、t.hpとthief.hpはメモリの同じ場所を指すことになるため) }継承
Matango.java//キノコモンスターのクラスを作成 public class Matango { int hp = 50; char suffix; public Matango(char suffix) { this.suffix = suffix; } public void attack(Hero h) { System.out.println("キノコの攻撃 " + this.suffix); System.out.println("10のダメージ"); h.hp -= 10; } }PoisonMatango.javapublic class PoisonMatango extends Matango { int poisonCount = 5; public PoisonMatango(char suffix) { super(suffix); } public void attack(Hero h) { super.attack(h); if (this.poisonCount > 0) { System.out.println("さらに胞子をばらまいた"); int dmg = h.hp / 5; h.hp -= dmg; System.out.println(dmg + "ポイントのダメージ"); this.poisonCount--; } } }Hero.javapublic class Hero { String name; int hp = 150; public Hero(String name) { this.name = name; System.out.println("名前は" + this.name + "、体力は " + this.hp); } }Main.javapublic class Main { public static void main(String[] args) { Hero h = new Hero("ヒロタ"); Hero h2 = new Hero("ヒロタ2"); Matango m1 = new Matango('A'); m1.appear(); m1.attack(h); PoisonMatango pm1 = new PoisonMatango('A'); pm1.appear(); pm1.attack(h2); } }




