JavaDoc 読解~java.util.Observableクラスの使い方~

java.util.Observableクラス

このクラスは、Observerインターフェースと併用するようにできています。デザインパターンの「Observerパターン」です。

処理の概要

Observableクラスに登録されたObserverクラス(Observerインターフェースをimplementsしたクラス)のupdateメソッドを
変更の通知があったときに呼び出す。

実装してみた

Observableクラスにメインメソッドを実装しました。はじめはObserverクラスに何かしらの変更があったときにupdate処理が走るのかと思ったのですが
次のメソッドが動いたときに走るようです。

Observable#setChanged()とObservable#notifyObservers()を呼び出すとObserverクラスのupdateが起動します。

Observableを継承して作る

import java.util.Observable;
import java.util.function.Function;

public class ObserverSample extends Observable {
    /** 引数String, 返却値Stringのメソッド */
    private Function<String, String> func;

    public ObserverSample(Function fun) {
        this.func = fun;
    }

    public void execute(String str) {
        System.out.println(func.apply(str));
    }

    public static void main(String[] ags) {
        // Functionに意味はないです。実装したときの残骸です。。。
        ObserverSample sample = new ObserverSample(str -> {
            return "aaa: " + str;
        });

        ChildOverver ovs = new ChildOverver("aaa");
        ChildOverver ovs1 = new ChildOverver("bbb");
        ChildOverver ovs2 = new ChildOverver("ccc");
        sample.addObserver(ovs);
        sample.addObserver(ovs1);
        sample.addObserver(ovs2);

        sample.setChanged();
        sample.notifyObservers();
        System.out.println("^^^^^^^^^^^^^^^^^^^^");
        sample.setChanged();
        sample.notifyObservers("pppppp");
    }
}

Observerクラス

import java.util.Observable;
import java.util.Observer;

public class ChildOverver implements Observer {
    private String str;
    public ChildOverver(String str) {
        this.str = str;
    }
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Param is " + str);
        System.out.println("Count: " + o.countObservers());
        System.out.println("arg: " + arg);
    }

    public void setStr(String newStr) {
        this.str = newStr;
    }
}

プログラムの実行結果

Param is ccc
Count: 3
arg: null
Param is bbb
Count: 3
arg: null
Param is aaa
Count: 3
arg: null
^^^^^^^^^^^^^^^^^^^^
Param is ccc
Count: 3
arg: pppppp
Param is bbb
Count: 3
arg: pppppp
Param is aaa
Count: 3
arg: pppppp

Java Doc 読解〜System.out〜

イントロダクション

標準入力に関してやったので、今度は標準出力に関してやります。

上記のキャプチャ「out」が標準出力になります。
でもこれは。。。

標準出力

一番初めのプログラムでこのクラスを使用しています。
コンソール出力がこの「標準出力」にあたります。

public static void main(String[] args) {
   System.out.println("Hello World");
}

以上です。

でわでわ。。。


Java Doc読解 〜System.In〜

イントロダクション

標準入力、画面からの入力にはWebのフォームが一番身近に感じる人が多いのではないでしょうか?フォームの出てくる、もっと昔からコンソール入力があるんです。その入力のことを「標準入力」と呼びます。

そして、Systemクラスのフィールドにいます。(実態はInputStreamクラスです)
JavaDocAPIはこちら

標準入力の実装

四の五の言わずにサンプルコードを下に示します。

System.out.println("test1 入力開始");
// 配列は動的に扱うときに大変だ。。。
byte[] moji = new byte[5];
try {
   System.in.read(moji);
} catch(Exception e) {
   e.printStackTrace();
}
System.out.println("入力じた文字:" + new String(moji));

byte配列を用意(宣言した時にメモリの領域が確保されます)、サンプルコードでは5バイト分を用意しています。標準入力を受けて入力した文字を表示します。

シンプルですね(笑)
メインメソッドからちゃんと作成したものはGitにアップしております。

こんな感じです。
でわでわ。。。

Java Doc 読解〜BufferedWriter〜

イントロダクション

BufferedWiterはReaderインターフェースとセットにして使用することが多いです。ちなみにBufferedReaderに関してはこちらです。

BufferedWriter

キャプチャを撮ってみました。ぶっちゃけた話細かいことより「どうつかうの?」が知りたいと思っているところに詳細なクラス関係などを説明されても困るので、筆者は困ったので、早速使い方を以下に示します。

// TODO-[IOExceptionのthrows文、try〜chatchなどを使用します。
FileReader fileRead = new FileReader(new File("./test.txt"));
BufferedReader read = new BufferedReader(fileReader);
BufferedWriter writer = new BufferedWriter(
                           new FileWriter(new File("./out.txt)));
// 読み込む行
String line = null;
while((line = read.readLine()) != null) {
   witer.write(line);
}
// ファイルを閉じる
writer.close();

Readerクラスの記載にも同じコードがあります。
FileReaderでも、通常の文字列でも良いのでwriteメソッドでファイルに出力します。そして、出力が終わったらcloase()してください。ファイルが閉じていない状態だと、対象のファイルが読めなかったり、余計なデーモン閣下が残ったりとして面倒臭いです。
※デーモン閣下→デーモン(デーモン・プロセス)画面上に表示されないけれど画面の裏側にいきているプロセスのことを言います。サーバなど起動しているときサーバーは画面上に出て来ず、裏側で起動している場合があります。この様なプロセスのことをデーモン(デーモン・プロセス)と呼びます。

Readerと合わせて使用することが多いです。他にも標準入力から使用することもあります。※ゲームを作成しようとしたら標準入力は必須になります。

サンプルコード

独自に作成したKozaManagerクラスです。これは、口座情報をファイルに書き出すという処理を実装しています。

/**
 * Copyright (c) 2019-present Coder Bank All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 * Neither the name Coder Bank nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 */
package jp.zenryoku.apps.atm.manage;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import jp.zenryoku.apps.atm.data.Data;

/**
 * 口座の管理(登録、更新、削除)を行うクラス
 * @author takunoji
 *
 * 2019/09/21
 */
public class KozaManager {
    /** ファイルへの書き出しクラス */
    private BufferedWriter write;
    /** ファイルの読み込みクラス */
    private BufferedReader read;
    /** 取得(作成)するファイルクラス */
    private File file;
    /** ファイルのパス */
    private static final String FILE_PATH = "resources/koza.csv";

    /** コンストラクタ */
    public KozaManager() {
        // 操作するファイルを指定する
        file = new File(FILE_PATH);
        try {
            write = new BufferedWriter(new FileWriter(file, true));
            if (file.exists()) {
                read = new BufferedReader(new FileReader(file));
            }
        } catch (IOException ie) {
            ie.printStackTrace();
            System.out.println("ファイルオープンに失敗しました。" + ie.getMessage());
            System.exit(-1);
        }
    }

    /** デストラクタ */
    @Override
    protected void finalize() throws Throwable {
        // フィールド変数の後始末
        file = null;
        read.close();
        write = null;
        read = null;
    }

    /** 作成するファイルが存在するかチェック */
    public boolean isFile() {
        return file.exists();
    }

    /**
     * 出力するCSVのヘッダー部分を作成する。
     * @return CSVヘッダーの文字列(カンマ区切り)
     */
    private String createCSVHeader() {
        return "名前, パスワード";
    }

    /**
     * データクラスを受け取り、CSVファイルを出力する(書き出しを行う)
     * @param data コーダー銀行のユーザー情報
     */
    public void dataOutput(Data data) throws IOException {
        if (file.canWrite() == false) {
            throw new IOException("ファイルの書き込みができません: " + file.getAbsolutePath());
        }
        // おおよそのデータサイズを指定すると余計なメモリを使用しなくて済む
        StringBuilder build = new StringBuilder(50);
        // ファイルそ新規で作成するとき
        if (file.exists() == false) {
            // ヘッダー部分の出力
            build.append(this.createCSVHeader());
            // ファイル書き込み処理
            write.write(build.toString());
            write.newLine();
        }
        // StringBuilderのクリア
        build.setLength(0);
        // データ部分の書き込み
        build.append(data.getName() + ",");
        build.append(data.getPassword());
        write.write(build.toString());
        write.newLine();
        write.close();
    }

    /**
     * ファイルを読み込みデータをリストにして返却する
     * @return List<Data> CSVファイルのデータリスト
     */
    public List<Data> readFile() {
        List<Data> list = new ArrayList<>();
        String line = null;
        try {
            while((line = read.readLine()) != null) {
                String[] lineData = line.split(",");
                // lineData[0]: 名前, lineData[1]: パスワード
                list.add(new Data(lineData[0], lineData[1]));
            }
        } catch(IOException ie) {
            ie.printStackTrace();
            System.exit(-1);
        }
        return list;
    }

    /**
     * フィールドのfileを返却する。
     * @return file
     */
    public File getFile() {
        return this.file;
    }
}

でわでわ。。。

Java Doc読解 BufferedReader

イントロダクション

Java Docの内容を読んで、理解します。今回はBufferedReaderを理解します。
以下のリンク先がJavaDocになります。
JavaDoc~BufferedReader~

BufferedReaderはファイル読み個処理の時によく使用するクラスです。

下のコードは、サンプルコードです。

  1. responseは取得したデータ(文字列)を返却するための変数
  2. Files.newBufferedReader()で、このPCの使用する文字エンコードでクラスの生成(インスタンス化)
  3. whileの条件としてreadLine()で取得した文字列(line)がnullでないならば繰り返す
  4. SEPは改行コード
StringBuilder response = new StringBuilder();
final String SEP = System.getProperty("line.separator");
try {
    BufferedReader read =  Files.newBufferedReader(Paths.get("resources/title.txt"), Charset.forName(System.getProperty("file.encoding")));
    String line = "";
    while((line = read.readLine()) != null) {
        response.append(line);
        response.append(SEP);
    }
} catch(IOException e) {
    e.printStackTrace();
}

サンプル動画

読み込み

これは、自分のやり方ですが…

初めに「すべての実装されたインターフェース」を見ます。知っているものがあれば、理解は早いです。メソッドの使い方は全く同じになるので…

次は、クラスの説明部分を読みます。ここまで、上から順に読んでいます。

コンストラクタや、メソッドに関してはナナメ読みして使えそうなものをチョイスします。

Java Docのポイント

結局のところは、使えれば良い(処理の中身は必要に応じて)ので用途を理解できるようになれば、おっけ

Java Docの理解には、以下の事を分かっておくと楽です。

  1. 継承関係について
  2. 対象クラスのベースになるフレームワークの理解、これはリストやマップであれば、コレクションフレームワークになるし、JavaFXであればJavaFXのフレームワークになります。

BufferedReader

BufferedReaderの使用サンプルを下に示します。※上記のサンプルとは別の書き方です。処理内容はほぼ同じ

// リーダー作成
Reader reader = new InputStreamReader(System.in);
// コンストラクタ
BufferedReader buf = new Bufferedreader(reader);

こんな感じです。ちなみにファイルの読み込みを行うときは

// TODO-[IOExceptionのthrows文、try〜chatchなどを使用します。
FileReader fileRead = new FileReader(new File("./test.txt"));
BufferedReader read = new BufferedReader(fileReader);
BufferedWriter writer = new BufferedWriter(
                           new FileWriter(new File("./out.txt)));
// 読み込む行
String line = null;
while((line = read.readLine()) != null) {
   witer.write(line);
}
// ファイルを閉じる
writer.close();

Readerクラスを継承したクラスがJava Docに記載されているのでどれを選んでもおっけーです。ちなみにBufferedWriterに関しても記載しております。

既知のサブクラスに記載されてます。

関連するインターフェースなど

そして、対象のクラスの継承関係(親子関係)

早い話が、Readerクラスを親に持っていますよ。ということ

BufferedReaderと似たクラスは何かな?と思ったら親クラスのReaderクラスを参照してみれば良い。

以下のようなクラスが兄弟クラスとして見ることができます。
BufferedReader,
・ CharArrayReader,
FilterReader,
InputStreamReader,
PipedReader,
StringReader

こんな感じで開拓して行くのも面白いのではないでしょうか?

でわでわ。。。