(同じ利用者による、間の1版が非表示)
8行目: 8行目:
* Setインターフェース(重複NG・順序保証なし):HashSet、LinkedHashSet、TreeSet
* Setインターフェース(重複NG・順序保証なし):HashSet、LinkedHashSet、TreeSet
* Mapインターフェース(ペアの値):HashMap、LinkedHashMap、TreeMap
* Mapインターフェース(ペアの値):HashMap、LinkedHashMap、TreeMap
* 配列の方がメモリ効率や性能は高いが、自動的に要素が増える ArrayList の方が多く使われる
* 配列の方がメモリ効率や性能は高いが、'''自動的に要素が増える ArrayList の方が多く使われる'''
* コレクションフレームワークは基本データ型を格納できない。オートボクシング機能が助かる
* コレクションフレームワークは'''基本データ型を格納できない'''。オートボクシング機能が助かる
* 必要な場面もあるので、for文・拡張for文・イテレータ。リストから要素を取り出すこの3種類の方法はすべて利用できるようにしておく
* 必要な場面もあるので、for文・拡張for文・イテレータ。リストから要素を取り出す'''この3種類の方法はすべて利用できるようにしておく'''
* コレクションインスタンスは十把一絡げで取り扱う。これがメリットの大きい一般的なやり方。List<String> = new ArrayList<String>(); など
* コレクションインスタンスは十把一絡げで取り扱う。これがメリットの大きい一般的なやり方。List<String> = new ArrayList<String>(); など
* HashSet内のデータを取り出す場合の順序は基本的に不明。しかし、LinkedHashSet(格納した順序)や TreeSet(辞書順)を使えば順序で取り出せる
* HashSet内のデータを取り出す場合の順序は基本的に不明。しかし、LinkedHashSet(格納した順序)や TreeSet(辞書順)を使えば順序で取り出せる
* 自分が開発したクラスをコレクションで利用する場合、equals() や hashCode() を正しくオーバーライドしていないとコレクションは正しく動かない
* 自分が開発したクラスをコレクションで利用する場合、'''equals() や hashCode() を正しくオーバーライド'''していないとコレクションは正しく動かない
* 利用すべきコレクションクラスの選び方は『実践』p107 を参照
* '''利用すべきコレクションクラスの選び方'''は『実践』p107 を参照
* 基盤5メソッド:Objectクラスが持っている(全てのクラスが継承する)機能が5つある
* '''基盤5メソッド''':Objectクラスが持っている(全てのクラスが継承する)機能が5つある
* toString(文字列表現を得る)、equals(等価判定をする)、hashCode(ハッシュ値を得る)、compareTo(大小関係を判定する)、clone(複製する)
* toString(文字列表現を得る)、equals(等価判定をする)、hashCode(ハッシュ値を得る)、compareTo(大小関係を判定する)、clone(複製する)
* toStringメソッド:インスタンスの情報を文字列で示す。クラスを作ったら適切にオーバーライドすべき
* toStringメソッド:インスタンスの情報を文字列で示す。'''クラスを作ったら適切にオーバーライド'''すべき
* equalsメソッド:2つのインスタンスを比較して等価(内容が同じ)であるかどうかを判定する。等値(メモリアドレス完全に一致している)かの判定ではない。クラスを作ったら必ず適切にオーバーライドすべき
* equalsメソッド:2つのインスタンスを比較して等価(内容が同じ)であるかどうかを判定する。等値(メモリアドレス完全に一致している)かの判定ではない。クラスを作ったら必ず適切にオーバーライドすべき
* JVM は ArrayList から同じものを探すために equlasメソッドを利用するため
* JVM は ArrayList から同じものを探すために equlasメソッドを利用するため
* さらに、Hash系のコレクションクラスでは等価判定にハッシュ値を利用するので hashCodeメソッドも正しくオーバーライドしておく必要がある
* さらに、Hash系のコレクションクラスでは等価判定にハッシュ値を利用するので hashCodeメソッドも正しくオーバーライドしておく必要がある
* JVM はまずはハッシュ値によって「だいたい同じか?」を判定し、ハッシュ値が一致した時に限り equalsメソッドによる厳密な判定へと移る
* JVM はまずはハッシュ値によって「だいたい同じか?」を判定し、ハッシュ値が一致した時に限り equalsメソッドによる厳密な判定へと移る
* 開発するクラスが自然順序(銀行口座番号など)を持っているなら Comparableインターフェースを実装すると後々便利
* 開発するクラスが'''自然順序(銀行口座番号など)を持っているなら Comparableインターフェースを実装'''すると後々便利
* インスタンスの完全コピーに対応したクラスを作りたい場合は Cloneableインターフェースを実装して、さらに cloneメソッドをオーバーライドする
* '''インスタンスの完全コピーに対応したクラスを作りたい場合'''は Cloneableインターフェースを実装して、さらに cloneメソッドをオーバーライドする
* インスタンスの複製には深いコピー(deep copy)と浅いコピー(shallow copy)がある
* インスタンスの複製には深いコピー(deep copy)と浅いコピー(shallow copy)がある
* Java はデータの型を厳格にチェックするので安全に開発を進めることができる
* Java はデータの型を厳格にチェックするので安全に開発を進めることができる
* 「型安全」は、変数に予期しない種類のデータが入ってしまうことを未然に防ぐための安全装置(リスクヘッジ)
* 「'''型安全'''」は、変数に予期しない種類のデータが入ってしまうことを未然に防ぐための安全装置(リスクヘッジ)
* ゆえに、型を厳格に扱わないプログラミング言語は「便利だが少し怖い」というイメージが正しい
* ゆえに、型を厳格に扱わないプログラミング言語は「便利だが少し怖い」というイメージが正しい
* 型を積極的に活用することにより、データをより厳密に扱うことができて不具合を減らせる
* 型を積極的に活用することにより、データをより厳密に扱うことができて不具合を減らせる
* コンパイルエラーは重大事故を未然に防ぐ安全装置。型安全を活用して、どんどんコンパイラにミスを探させよう!
* コンパイルエラーは重大事故を未然に防ぐ安全装置。型安全を活用して、'''どんどんコンパイラにミスを探させよう!'''
* Java には型安全のメリットをフル活用するために「ジェネリクス」や「列挙型」という仕組みが用意されている
* Java には'''型安全のメリットをフル活用するために「ジェネリクス」や「列挙型」という仕組み'''が用意されている
* ジェネリクスという特別な仕組みによって定義されている標準クラスは<>記法が可能。APIリファレンスでも <E> や <K,V> と表記されている
* ジェネリクスという特別な仕組みによって定義されている標準クラスは<>記法が可能。APIリファレンスでも <E> や <K,V> と表記されている
* ジェネリクスは自作クラスでも活用できる。ジェネリクスとはクラス作成時に型を確定できないときに「仮の型」で代用しておく方法
* ジェネリクスは自作クラスでも活用できる。'''ジェネリクスとは'''クラス作成時に型を確定できないときに'''「仮の型」で代用'''しておく方法
* ジェネリクスが定義されたクラスでは、クラス利用時にその時に都合の良い「型」を指定することができる
* ジェネリクスが定義されたクラスでは、クラス利用時にその時に都合の良い「型」を指定することができる
* 型を「仮決め」しているおかげでダウンキャストというリスクをとる必要がなくなっている
* 型を「仮決め」しているおかげで'''ダウンキャストというリスク'''をとる必要がなくなっている
* ちなみに、ジェネリクスでは指定できる型を予め制限することもできる。public class Pocket<E extends Character> など
* ちなみに、ジェネリクスでは指定できる型を予め制限することもできる。public class Pocket<E extends Character> など
* Java では、指定した種類の値だけを入れることができる「列挙型」というものを定義できる
* Java では、指定した種類の値だけを入れることができる「'''列挙型'''」というものを定義できる
* 列挙型では、その変数で許される具体的な型をカンマ区切りで列挙して宣言できる。enum AccountType { FUTSU, TOUZA, TEIKI; }
* 列挙型では、その変数で'''許される具体的な型をカンマ区切りで列挙'''して宣言できる。enum AccountType { FUTSU, TOUZA, TEIKI; }
* どのようなものを第1級オブジェクトとして扱えるかは、そのプログラミング言語の便利さや開発効率を決定づける
* どのようなものを第1級オブジェクトとして扱えるかは、そのプログラミング言語の便利さや開発効率を決定づける
* 例えば、C言語はインスタンスを第1級オブジェクトとして扱えないためオブジェクト指向プログラミングは困難
* 例えば、C言語はインスタンスを第1級オブジェクトとして扱えないためオブジェクト指向プログラミングは困難
46行目: 46行目:
* もちろん、これもメソッドが格納されているメモリアドレスを参照する参照型
* もちろん、これもメソッドが格納されているメモリアドレスを参照する参照型
* Java8以降では、処理ロジックを事前に何らかのクラス内のメソッドとしてわざわざ定義しなくても、随時、生成して利用することができる
* Java8以降では、処理ロジックを事前に何らかのクラス内のメソッドとしてわざわざ定義しなくても、随時、生成して利用することができる
* このように、簡易的に(わざわざクラスを作らないで)メソッドを利用したい場合に使うのが「ラムダ式」と呼ばれる記法
* このように、'''簡易的に(わざわざクラスを作らないで)メソッドを利用したい場合に使うのが「ラムダ式」'''と呼ばれる記法
* ラムダ式を使うと、ファンクションをその場で生み出して、変数に割り当てたり呼び出したりできる
* ラムダ式を使うと、ファンクションをその場で生み出して、変数に割り当てたり呼び出したりできる
* ラムダ式では条件が許せば、様々な省略した書き方をすることができる
* ラムダ式では条件が許せば、様々な省略した書き方をすることができる
54行目: 54行目:
* ラムダ式では、その時点でコードに記述されている変数全てを利用できるが書き換えることはできない
* ラムダ式では、その時点でコードに記述されている変数全てを利用できるが書き換えることはできない
* 関数オブジェクトやラムダ式は、他の機能(配列やコレクションなど)と組み合わせて使うことによって真価を発揮する。詳細は『実践』p189
* 関数オブジェクトやラムダ式は、他の機能(配列やコレクションなど)と組み合わせて使うことによって真価を発揮する。詳細は『実践』p189
* streamメソッドとラムダ式を組み合わせて使うことによって、各要素に様々な一括処理を行ったり集計を取ったりエレガントな一括処理ができる
* '''streamメソッドとラムダ式を組み合わせて使う'''ことによって、各要素に様々な一括処理を行ったり集計を取ったり'''エレガントな一括処理'''ができる
* for (Integer i : list1) { System.out.println(i * 2); }。これが・・
* for (Integer i : list1) { System.out.println(i * 2); }。これが・・
* list1.stream().forEach(i -> System.out.println(i * 2)); となる
* list1.stream().forEach(i -> System.out.println(i * 2)); となる
* さらにマルチコアCPU環境において、streamメソッドの代わりに parallelStreamメソッドを使うと JVM は並列処理を行うようになり2倍処理スピードがアップする
* さらにマルチコアCPU環境において、streamメソッドの代わりに parallelStreamメソッドを使うと JVM は並列処理を行うようになり2倍処理スピードがアップする
* JVM は天才たちが作った仮想マシン環境なので、内部は非常に複雑な構造をしている
* JVM は天才たちが作った仮想マシン環境なので、内部は非常に複雑な構造をしている
* Java では、Java開発者が JVM自体の内部機構にアクセスして、その情報を取得したり利用したりできる
* Java では、Java開発者が '''JVM自体の内部機構にアクセス'''して、その情報を取得したり利用したりできる
* 例えば、Javaのバージョン、インストール先、動作OS、メモリの状態、実行ユーザ名などの情報を取得できたり、OS内の他のプログラムを呼び出したりできる
* 例えば、Javaのバージョン、インストール先、動作OS、メモリの状態、実行ユーザ名などの情報を取得できたり、OS内の他のプログラムを呼び出したりできる
* 「Write once, Run anywhere」も100%ではない。例えば、改行コード1つ取っても Linux環境と Mac環境では画面表示が異なってしまう
* 「Write once, Run anywhere」も100%ではない。例えば、改行コード1つ取っても Linux環境と Mac環境では画面表示が異なってしまう
* そこで、あらゆる動作OSを想定した上で適切な改行コードを出力するように「line.separator」システムプロパティを使う必要があったりする
* そこで、あらゆる動作OSを想定した上で適切な改行コードを出力するように「line.separator」システムプロパティを使う必要があったりする
* リフレクションAPI を利用すると、クラスやインターフェースに関する様々な情報を JVM に調べさせることができる。今まで実現不可能だったことも可能になる。例えば ↓
* リフレクションAPI を利用すると、'''クラスやインターフェースに関する様々な情報'''を JVM に調べさせることができる。今まで実現不可能だったことも可能になる。例えば ↓
* FQCN、クラス名部分のみ、所属パッケージ名、親クラス名、配列かどうか、インターフェースかどうか、列挙型かどうか、など
* FQCN、クラス名部分のみ、所属パッケージ名、親クラス名、配列かどうか、インターフェースかどうか、列挙型かどうか、など
* 本格的な開発においては、標準・非標準の様々な API を組み合わせて開発していくケースも多
* 本格的な開発においては、標準・非標準の様々な API を組み合わせて開発していくケースも多
* 例えば、「ログイン機能を実装するための14個のクラスファイル」や「暗号処理を実現する31個のクラスファイル」のように、複数のクラスファイルをまとめて利用する場合がほとんど
* '''例えば、「ログイン機能を実装するための14個のクラスファイル」や「暗号処理を実現する31個のクラスファイル」のように、複数のクラスファイルをまとめて利用する場合がほとんど'''
* ライブラリ:他の人に利用してもらうことを想定した複数のクラスファイルの集まりのこと。通常は JARファイル形式で提供される
* ライブラリ:他の人に利用してもらうことを想定した複数のクラスファイルの集まりのこと。通常は JARファイル形式で提供される
* 非標準ライブラリの中にはとても便利なものも多い。例えば、EqualsBuilder には正しい equlasメソッドのオーバーライドが既に実装されている
* '''非標準ライブラリの中にはとても便利なものも多い'''。例えば、EqualsBuilder には正しい equlasメソッドのオーバーライドが既に実装されている
* ログ出力を簡単に行ったり、コレクションを簡単に使うためのクラス群も充実していたりする
* ログ出力を簡単に行ったり、コレクションを簡単に使うためのクラス群も充実していたりする
* ログ出力には何らかの非標準ライブラリを利用することが一般的
* '''ログ出力には何らかの非標準ライブラリを利用することが一般的'''
* ただし、非標準ライブラリを利用する際にはライセンスに気をつける必要がある。オープンソース、プロプライエタリなど
* ただし、非標準ライブラリを利用する際には'''ライセンスに気をつける必要'''がある。オープンソース、プロプライエタリなど
* ライセンス違反にならないかどうかは自分で判断しない。リーダーや上司、法務部門に判断してもらう
* ライセンス違反にならないかどうかは自分で判断しない。リーダーや上司、法務部門に判断してもらう
* 「GPLに感染する」=「ソースコードを嫌でも開示しないといけない」=コピーレフト(リチャード・ストールマン)
* 「GPLに感染する」=「ソースコードを嫌でも開示しないといけない」=コピーレフト(リチャード・ストールマン)
99行目: 99行目:
* バイト情報用:BufferedInputStream、BufferedOutputStream
* バイト情報用:BufferedInputStream、BufferedOutputStream
* 少量のデータを何度も書き込み要求するよりも、データをひとまとまりにして1回で書き込んでしまった方が圧倒的に速く処理できる
* 少量のデータを何度も書き込み要求するよりも、データをひとまとまりにして1回で書き込んでしまった方が圧倒的に速く処理できる
* ファイルを読み書きするときは普通はバッファリングフィルタを併用する
* '''ファイルを読み書きするときは普通はバッファリングフィルタを併用'''する
* データフォーマット:データの保存形式や順序を定めたルール
* データフォーマット:データの保存形式や順序を定めたルール
* ファイルフォーマット:ファイル内のデータ構造のルール
* ファイルフォーマット:ファイル内のデータ構造のルール
* メッセージフォーマット:ネットワーク経由で伝送されるデータ構造のルール
* メッセージフォーマット:ネットワーク経由で伝送されるデータ構造のルール
* CSV形式:複数のデータをカンマ区切りで格納するデータフォーマット
* '''CSV形式''':複数のデータをカンマ区切りで格納するデータフォーマット
* CSV形式のデータを読み込むには Stringクラスの split()メソッドか、StringTokenizerクラスを利用
* CSV形式のデータを読み込むには Stringクラスの split()メソッドか、StringTokenizerクラスを利用
* プロパティファイル形式:CSV形式では力不足な場合に利用。キーと値のペアでデータを格納できる
* '''プロパティファイル形式''':CSV形式では力不足な場合に利用。キーと値のペアでデータを格納できる
* プロパティファイル形式は直感的に意味が分かりやすいのでよく利用される
* プロパティファイル形式は直感的に意味が分かりやすいのでよく利用される
* プロパティファイル形式の場合、ファイル拡張子は「.properties」を利用する
* プロパティファイル形式の場合、ファイル拡張子は「.properties」を利用する

2019年2月21日 (木) 11:03時点における最新版

第1部:Java の基本機能をより深く

  • プロジェクトなど本格的な開発現場では、便利で高機能な Java の機能を組み合わせて効率的に開発を進めます
  • 文字列操作の多くは、Stringクラスに備わっているメソッドを利用することで簡単に実現できます
  • ただし、スレッドを利用している時に Stringクラスを利用すると不具合につながる恐れがある
  • StringBuilder で利用する時のように、自身への参照を返すメソッドを連続して呼び出す方法をメソッドチェーンと呼ぶ
  • Javaコレクションフレームワーク:様々なデータ構造に対応した「データを格納するための入れ物」クラス
  • Listインターフェース(重複OK・順序保証あり):ArrayList、LinkedList。格納するデータの型を<>で指定(ジェネリクス)
  • Setインターフェース(重複NG・順序保証なし):HashSet、LinkedHashSet、TreeSet
  • Mapインターフェース(ペアの値):HashMap、LinkedHashMap、TreeMap
  • 配列の方がメモリ効率や性能は高いが、自動的に要素が増える ArrayList の方が多く使われる
  • コレクションフレームワークは基本データ型を格納できない。オートボクシング機能が助かる
  • 必要な場面もあるので、for文・拡張for文・イテレータ。リストから要素を取り出すこの3種類の方法はすべて利用できるようにしておく
  • コレクションインスタンスは十把一絡げで取り扱う。これがメリットの大きい一般的なやり方。List<String> = new ArrayList<String>(); など
  • HashSet内のデータを取り出す場合の順序は基本的に不明。しかし、LinkedHashSet(格納した順序)や TreeSet(辞書順)を使えば順序で取り出せる
  • 自分が開発したクラスをコレクションで利用する場合、equals() や hashCode() を正しくオーバーライドしていないとコレクションは正しく動かない
  • 利用すべきコレクションクラスの選び方は『実践』p107 を参照
  • 基盤5メソッド:Objectクラスが持っている(全てのクラスが継承する)機能が5つある
  • toString(文字列表現を得る)、equals(等価判定をする)、hashCode(ハッシュ値を得る)、compareTo(大小関係を判定する)、clone(複製する)
  • toStringメソッド:インスタンスの情報を文字列で示す。クラスを作ったら適切にオーバーライドすべき
  • equalsメソッド:2つのインスタンスを比較して等価(内容が同じ)であるかどうかを判定する。等値(メモリアドレス完全に一致している)かの判定ではない。クラスを作ったら必ず適切にオーバーライドすべき
  • JVM は ArrayList から同じものを探すために equlasメソッドを利用するため
  • さらに、Hash系のコレクションクラスでは等価判定にハッシュ値を利用するので hashCodeメソッドも正しくオーバーライドしておく必要がある
  • JVM はまずはハッシュ値によって「だいたい同じか?」を判定し、ハッシュ値が一致した時に限り equalsメソッドによる厳密な判定へと移る
  • 開発するクラスが自然順序(銀行口座番号など)を持っているなら Comparableインターフェースを実装すると後々便利
  • インスタンスの完全コピーに対応したクラスを作りたい場合は Cloneableインターフェースを実装して、さらに cloneメソッドをオーバーライドする
  • インスタンスの複製には深いコピー(deep copy)と浅いコピー(shallow copy)がある
  • Java はデータの型を厳格にチェックするので安全に開発を進めることができる
  • 型安全」は、変数に予期しない種類のデータが入ってしまうことを未然に防ぐための安全装置(リスクヘッジ)
  • ゆえに、型を厳格に扱わないプログラミング言語は「便利だが少し怖い」というイメージが正しい
  • 型を積極的に活用することにより、データをより厳密に扱うことができて不具合を減らせる
  • コンパイルエラーは重大事故を未然に防ぐ安全装置。型安全を活用して、どんどんコンパイラにミスを探させよう!
  • Java には型安全のメリットをフル活用するために「ジェネリクス」や「列挙型」という仕組みが用意されている
  • ジェネリクスという特別な仕組みによって定義されている標準クラスは<>記法が可能。APIリファレンスでも <E> や <K,V> と表記されている
  • ジェネリクスは自作クラスでも活用できる。ジェネリクスとはクラス作成時に型を確定できないときに「仮の型」で代用しておく方法
  • ジェネリクスが定義されたクラスでは、クラス利用時にその時に都合の良い「型」を指定することができる
  • 型を「仮決め」しているおかげでダウンキャストというリスクをとる必要がなくなっている
  • ちなみに、ジェネリクスでは指定できる型を予め制限することもできる。public class Pocket<E extends Character> など
  • Java では、指定した種類の値だけを入れることができる「列挙型」というものを定義できる
  • 列挙型では、その変数で許される具体的な型をカンマ区切りで列挙して宣言できる。enum AccountType { FUTSU, TOUZA, TEIKI; }
  • どのようなものを第1級オブジェクトとして扱えるかは、そのプログラミング言語の便利さや開発効率を決定づける
  • 例えば、C言語はインスタンスを第1級オブジェクトとして扱えないためオブジェクト指向プログラミングは困難
  • Java8以降では、データ、データ構造、インスタンスに加えてファンクション(関数)を第1級オブジェクトとして扱うことができる
  • ファンクションとは「Input → Process → Output構造の処理ロジックの部分」のこと。ファンクション名はなくても構わない
  • ゆえに、メソッドもクラスのためのファンクションの一種と言えるがメソッド(動作)には名称がつく
  • Java では、IntBinaryOperator func = Main::sub; のように、Mainクラスの subメソッドを変数 func に割り当てることができる
  • もちろん、これもメソッドが格納されているメモリアドレスを参照する参照型
  • Java8以降では、処理ロジックを事前に何らかのクラス内のメソッドとしてわざわざ定義しなくても、随時、生成して利用することができる
  • このように、簡易的に(わざわざクラスを作らないで)メソッドを利用したい場合に使うのが「ラムダ式」と呼ばれる記法
  • ラムダ式を使うと、ファンクションをその場で生み出して、変数に割り当てたり呼び出したりできる
  • ラムダ式では条件が許せば、様々な省略した書き方をすることができる
  • 引数が1つの場合は、型・括弧・return を省略できる。例 ↓
  • IntToDoubleFunction func = (int x) -> { return x * x * 3.14; };
  • IntToDoubleFunction func = x -> x * x * 3.14;
  • ラムダ式では、その時点でコードに記述されている変数全てを利用できるが書き換えることはできない
  • 関数オブジェクトやラムダ式は、他の機能(配列やコレクションなど)と組み合わせて使うことによって真価を発揮する。詳細は『実践』p189
  • streamメソッドとラムダ式を組み合わせて使うことによって、各要素に様々な一括処理を行ったり集計を取ったりエレガントな一括処理ができる
  • for (Integer i : list1) { System.out.println(i * 2); }。これが・・
  • list1.stream().forEach(i -> System.out.println(i * 2)); となる
  • さらにマルチコアCPU環境において、streamメソッドの代わりに parallelStreamメソッドを使うと JVM は並列処理を行うようになり2倍処理スピードがアップする
  • JVM は天才たちが作った仮想マシン環境なので、内部は非常に複雑な構造をしている
  • Java では、Java開発者が JVM自体の内部機構にアクセスして、その情報を取得したり利用したりできる
  • 例えば、Javaのバージョン、インストール先、動作OS、メモリの状態、実行ユーザ名などの情報を取得できたり、OS内の他のプログラムを呼び出したりできる
  • 「Write once, Run anywhere」も100%ではない。例えば、改行コード1つ取っても Linux環境と Mac環境では画面表示が異なってしまう
  • そこで、あらゆる動作OSを想定した上で適切な改行コードを出力するように「line.separator」システムプロパティを使う必要があったりする
  • リフレクションAPI を利用すると、クラスやインターフェースに関する様々な情報を JVM に調べさせることができる。今まで実現不可能だったことも可能になる。例えば ↓
  • FQCN、クラス名部分のみ、所属パッケージ名、親クラス名、配列かどうか、インターフェースかどうか、列挙型かどうか、など
  • 本格的な開発においては、標準・非標準の様々な API を組み合わせて開発していくケースも多
  • 例えば、「ログイン機能を実装するための14個のクラスファイル」や「暗号処理を実現する31個のクラスファイル」のように、複数のクラスファイルをまとめて利用する場合がほとんど
  • ライブラリ:他の人に利用してもらうことを想定した複数のクラスファイルの集まりのこと。通常は JARファイル形式で提供される
  • 非標準ライブラリの中にはとても便利なものも多い。例えば、EqualsBuilder には正しい equlasメソッドのオーバーライドが既に実装されている
  • ログ出力を簡単に行ったり、コレクションを簡単に使うためのクラス群も充実していたりする
  • ログ出力には何らかの非標準ライブラリを利用することが一般的
  • ただし、非標準ライブラリを利用する際にはライセンスに気をつける必要がある。オープンソース、プロプライエタリなど
  • ライセンス違反にならないかどうかは自分で判断しない。リーダーや上司、法務部門に判断してもらう
  • 「GPLに感染する」=「ソースコードを嫌でも開示しないといけない」=コピーレフト(リチャード・ストールマン)

第2部:外部リソースへのアクセス

  • プログラムがファイルにアクセスする方法:ランダムアクセス or シーケンシャルアクセス
  • 大量のデータを高速で扱えるシーケンシャルアクセスの方がファイル操作の基本的な手法
  • ファイルに書き込むには、java.ioパッケージの FileWriterクラスがよく利用される
  • ファイルの読み書きを高速にするためにデータは一旦「バッファ」に溜めておかれる
  • 「バッファ」という仕組みがないと、データ書き込みのたびにハードディスクのヘッダが動くことになる
  • flush()メソッドを呼び出すことによって強制的にデータ書き込みを JVM に指示できる
  • read() によりファイルから1文字を読み込む際、char型ではなく int型として返される
  • これは、ファイルの最後まで読み込んだことが -1 によって報告されるため
  • データを利用するときは char型にキャストして利用する
  • バイナリファイルは少ないデータ容量で済む、高速に処理できるなどの理由から転送や保存に利用される
  • 全く同じ文字でも、どの文字コード体系を利用するかによってバイト列としての表現は全く異なってしまう
  • ファイルを開いた後に閉じ忘れると致命的な不具合につながるので、ファイルを開いたら必ず閉じる
  • try 直後のカッコ内でファイルオープンやデータベース接続をすると勝手に後片ずけをしてくれる
  • JVM が利用する外の世界のデータは「実際に読み込んでみないとそもそもサイズは分からない」
  • ゆえに、外部データはシーケンシャルに少しずつ処理するのが JVM の基本的なアプローチ(ストリーム)
  • 通常ストリームは JVM 外部のデータを少しずつ読み書きする際に利用するが、JVM 内部のデータ読み書きにも応用することができる
  • フィルタ:ストリームの途中に様々な変換処理をする部品(インスタンス)を挟むことが可能
  • 例えば、本来はとても複雑な処理である「データの暗号化」も CipherOutputStreamフィルタを1つ挟むだけで簡単に実現できる
  • フィルタはあくまでもストリームに付加的に接続される道具。ゆえに、フィルタ単独で new はできない
  • 利用頻度が高い java.ioパッケージのバッファリングフィルタ。データをバッファに溜めてくれる
  • 文字情報用:BufferedReader、BufferedWriter
  • バイト情報用:BufferedInputStream、BufferedOutputStream
  • 少量のデータを何度も書き込み要求するよりも、データをひとまとまりにして1回で書き込んでしまった方が圧倒的に速く処理できる
  • ファイルを読み書きするときは普通はバッファリングフィルタを併用する
  • データフォーマット:データの保存形式や順序を定めたルール
  • ファイルフォーマット:ファイル内のデータ構造のルール
  • メッセージフォーマット:ネットワーク経由で伝送されるデータ構造のルール
  • CSV形式:複数のデータをカンマ区切りで格納するデータフォーマット
  • CSV形式のデータを読み込むには Stringクラスの split()メソッドか、StringTokenizerクラスを利用
  • プロパティファイル形式:CSV形式では力不足な場合に利用。キーと値のペアでデータを格納できる
  • プロパティファイル形式は直感的に意味が分かりやすいのでよく利用される
  • プロパティファイル形式の場合、ファイル拡張子は「.properties」を利用する
  • プロパティファイル形式の読み書きには java.utilパッケージの Propertiesクラスが利用される
  • Propertiesクラスは全てのデータを文字列として扱う。ゆえに、整数や boolean型は明示的に型変換する必要がある
  • 勇者データと一緒に勇者の武器データも一緒に保存したいなど、ネストしたデータ構造を利用したい場合は XML形式がオススメ
  • XML形式を扱うには JAXP が利用できる
  • XML形式よりも読みやすいデータ形式としては最近 JSON形式がよく利用される
  • オブジェクトの直列化:インスタンスの全フィールド情報をとにかく楽に保存したい場合に利用できる
  • 複雑なデータ構造を持つインスタンス内の全データを 0 と 1 の単純な羅列に並ばせることから「直列化」と呼ばれる
  • インスタンスを直列化で保存できるようにするためには java.io.Serializable を実装する必要がある
  • 直列化するインスタンスが仮にクラス型のフィールドを持っていたとしても、そのクラス型が Serializable を実装していたら連鎖的にその has-a インスタンスも直列化で保存される
  • Serializable を実装して直列化保存に対応した場合、仕様変更後の復元を予防するためにシリアルバージョンUIDを宣言しておく
  • java.net 高水準API:簡単に使えるが細かい操作はできない(ざっくり URL を指定するなど)
  • java.net 低水準API:細かい操作ができるが複雑で手間がかかる(ポートやソケットを指定するなど)
  • リアルタイムの対戦ゲームなどを作るには低水準API を利用することになる
  • java.net.Socketクラスを利用することで TCP/IP接続をコントロールできる
  • 接続後のデータ書式や通信手順は、上位のプロトコルの形式を利用する
  • 複数の相手から同時に接続を受け付けるような本格的なサーバプログラムの開発には、別途スレッドやセキュリティなどについて学習する必要がある
  • より大量のデータを効率的かつ安全、高速に保存、検索するためにはデータベースを利用する
  • データベースを使うと、複雑なデータ検索や書き込みも簡単に行える
  • Javaプログラムの中で複雑なデータ処理を記述する必要がなくなる
  • データベースシステムで実現されている、専門家による長年の研究に基づいた様々な手法やアイディアを利用できる
  • Java で独自に開発するファイルを使った処理よりもデータベースを使った処理の方が圧倒的に高速で安全
  • 更新系SQL文では「executeUpdate()」を利用。検索系SQL文では「executeQuery()」を利用
  • 変更されるパラメータがある場合は PreparedStatementクラスを利用して、SQL文の雛形を準備する
  • SQL文の結果データは ResultSetオブジェクトとして返ってくる
  • next() は最終行で false を返す
  • 基本的には while で回しながら next() でカーソルを進めて、getInt、getString でデータを取得する
  • 2行以上(複数行)の結果表が返される可能性がある場合、while (rs.next()) を利用
  • 0行か1行の結果表が返される可能性がある場合、if (rs.next()) を利用
  • JDBC を使えば、複数のSLQ要求も単一トランザクションとして送信できる

第3部:効率的な開発