プログラミングBlog

プログラミング学習用

ちょいちょい書いてます

開発アプリサークル Java講座② 2020-11-21(土)

今回はinterfaceについて

interfaceを英訳すると・・・接点、接続、等
interfaceに書かれたメソッドは中身がない状態です。
classに対して実装を行い、interfaceに書かれた中身のないメソッドをclassの中で記述し、何をするかを決めることで役割を果たします。
イメージとしては機能(class)に部品(interface)を追加していく。
まずは3つのinterfaceを作ります。

検索用のinterface

// 検索
public interface Find {

    String FindOne();

    List<String> FindAll();
}

更新用のinterface

// 更新
public interface Update {

    List<String> UpdateOne(String TtelephoneNumber);

    List<String> UpdateAll(List<String> telephoneNumberList);
}

削除用のinterface

// 削除
public interface Delete {

    List<String> DeleteOne();

    List<String> DeleteAll();
}

上記のinterfaceにはまだどんな動作をするかを実装していないため、単体では使うことができません。 2つのクラスを作成し、先ほど作った3つのinterfaceを実装していきます。

TelephoneNumberクラス

public class TelephoneNumber implements Find, Update, Delete{

    private List<String> telephoneNumberList = new ArrayList<String>() {
        {
            add("00011232345");
            add("00023241234");
            add("00021341413");
        }
    };

    // 一件検索
    @Override
    public String FindOne() {
        return this.telephoneNumberList.get(0);
    }

    // 全件検索
    @Override
    public List<String> FindAll() {
        return this.telephoneNumberList;
    }

    // 一件削除
    @Override
    public List<String> DeleteOne() {
        this.telephoneNumberList.remove(0);
        return telephoneNumberList;
    }

    // 全件削除
    @Override
    public List<String> DeleteAll() {
        this.telephoneNumberList.clear();
        return telephoneNumberList;
    }

    // 一件更新
    @Override
    public List<String> UpdateOne(String telephoneNumber) {
        telephoneNumberList.set(0, telephoneNumber);
        return telephoneNumberList;
    }

    // 全件更新
    @Override
    public List<String> UpdateAll(List<String> telephoneNumberList) {
        this.telephoneNumberList = telephoneNumberList;
        return this.telephoneNumberList;
    }
}

Placeクラス

public class Place implements Find, Update, Delete{

    private List<String> placeList = new ArrayList<String>() {
        {
            add("兵庫");
            add("大阪");
            add("京都");
        }
    };

    // 一件検索
    @Override
    public String FindOne() {
        return this.placeList.get(0);
    }

    // 全件検索
    @Override
    public List<String> FindAll() {
        return this.placeList;
    }

    // 一件削除
    @Override
    public List<String> DeleteOne() {
        placeList.remove(0);
        return placeList;
    }

    // 全件削除
    @Override
    public List<String> DeleteAll() {
        placeList.clear();
        return placeList;
    }

    // 一件更新
    @Override
    public List<String> UpdateOne(String place) {
        placeList.set(0, place);
        return placeList;
    }

    // 全件更新
    @Override
    public List<String> UpdateAll(List<String> placeList) {
        this.placeList = placeList;
        return this.placeList;
    }
}

実行してみます。

public class Main {

    public static void main(String[] args) {

        TelephoneNumber telephoneNumber = new TelephoneNumber();
        Place place = new Place();

        // 検索
        System.out.println("一件検索" + ":" + telephoneNumber.FindOne());
        System.out.println("全件検索" + ":" + telephoneNumber.FindAll());

        System.out.println("一件検索" + ":" + place.FindOne());
        System.out.println("全件検索" + ":" +place.FindAll());

        List<String> telephoneNumberList = new ArrayList<String>()
        {
            {
                add("111111111");
                add("222222222");
                add("333333333");
            }
        };

        List<String> placeList = new ArrayList<String>()
        {
            {
                add("愛媛");
                add("北海道");
                add("沖縄");
            }
        };

        // 更新
        System.out.println("一件更新" + ":" + telephoneNumber.UpdateOne("000000000"));
        System.out.println("全件更新" + ":" + telephoneNumber.UpdateAll(telephoneNumberList));

        System.out.println("一件更新" + ":" + place.UpdateOne("福岡"));
        System.out.println("全件更新" + ":" + place.UpdateAll(placeList));

        // 削除
        System.out.println("一件削除" + ":" + telephoneNumber.DeleteOne());
        System.out.println("全件削除" + ":" + telephoneNumber.DeleteAll());

        System.out.println("一件削除" + ":" +place.DeleteOne());
        System.out.println("全件削除" + ":" +place.DeleteAll());
    }
}

f:id:Tokuty:20201123005220p:plain
interface側から見るとどのクラスでどんな処理をしているかが見やすいため、ほかの人が見る時にわかりやすいというメリットがありそうです。 後は、interfaceに書かれたメソッドは必ずオーバーライドして実装しなければならないので処理の実装抜けがなくなりますね。 今回は各クラスに実装したinterfaceのメソッドが同じ動きになるようにしましたが、別の動きを加えることも可能です。

interfaceのルール

変数とメソッドの記述可能。
変数はpublic static final となる。
多重実装が可能。 実装したクラスで必ずオーバーライドしなければいけない
オーバーライドとは・・・メソッド名と引数が同じ名前。引数のデータ型が同じで、戻り値のデータ型も同じ。アクセス修飾子が親と同じかそれより広い。

開発アプリサークル Java講座① 2020-11-14(土)

今回はクラス(model)について

Springフレームワークの依存関係を追加する時にlombockがあると思いますが、 modelを作る上で必要な部分がわからなくなってしまうので学習しました。
Employee(従業員)を作ってみましょう。まずはlombokとの比較からみていきましょう。

lombokとの比較例

@Data
public class Employee {
    // フィールド
    private int id;
    private String name;
    }
}

lombockを使うとフィールドに変数を宣言するだけで後はアノテーションがいい感じに処理をしてくれます。
@Getter @Setter @ToString @EqualsAndHashCode @Constructor この5個のアノテーションが付与されます。
@Getter @Setter このふたつが重要なので書いていきます。

public class Employee {
    // フィールド
    private int id;
    private String name;

    // getter
    public int getId() {
        return this.id;
    }

    // setter
    public void setId(int id) {
        this.id = id;
    }

    // getter
    public String getName() {
        return this.name;
    }

    // setter
    public void setId(String name) {
        this.name = name;
    }
}

書くコードがだいぶ増えましたが、
getterとsetterがないとprivateな変数の値を別のクラスで取り出したり、設定したりができなくなるのでかなり重要です。 lombockについてはここでいったん終了し、次はコンストラクターを作っていきます。
コンストラクタを書くことで、インスタンス宣言時にそのクラスにある変数の値を設定することができます。
コンストラクタとは・・・インスタンス生成した時に最初に呼びだされる場所のこと

// コンストラクタ
    Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }

Employeeクラスにこちらを追加。
Employeeクラスを呼び出してみましょう。

public class Main {
    public static void main(String[] args) {
        Employee A = new Employee(1, "A");

        System.out.println(A.getId());
        System.out.println(A.getName());;
    }
}

f:id:Tokuty:20201121140044p:plain
コンストラクタでインスタンス生成時に値を設定し、Getterで呼び出しています。
次はCompany(会社)を作ってみます。

public class Company {

    public String companyName;

    public Employee customer;

    Company(String companyName, Employee customer) {
        this.companyName = companyName;
        this.customer = customer;
    }

    // getter
    public String getCompanyName() {
        return this.companyName;
    }

    // setter
    public void setId(String companyName) {
        this.companyName = companyName;
    }

    // getter
    public Employee getCustomer() {
        return this.customer;
    }

    // setter
    public void setCustomer(Employee customer) {
        this.customer = customer;
    }
}

コンストラクターの部分で会社名とEmployee(社員)を設定するようにしてみました。
イメージは会社に属している社員。
実行してみます。

public class Main {

    public static void main(String[] args) {
        Employee A = new Employee(1, "A");

        Company company = new Company("KAISYA", A);

        System.out.println(company.getCompanyName());
        System.out.println(company.getCustomer().getName());
    }
}

f:id:Tokuty:20201121141000p:plain
無事、会社名と会社に属している会社員名が表示されました。

SpringAppをCloneした後、Eclipseで開いたら認識されていなかった場合

Eclipseワークスペースを開くとプロジェクトが見つからない。。。
Clone先のフォルダにはプロジェクトがあるのでどうやら認識されていないらしい。。
以下対処方法

①ファイル→ファイルシステムからプロジェクトを開く

f:id:Tokuty:20201115214849p:plain

②プロジェクトをインポート

ディレクトリーからプロジェクトを選ぶと自動で全てのプロジェクトを選択してくれる。 f:id:Tokuty:20201115214824p:plain これでプロジェクトは見れるようになりましたが、アプリケーションはまだ起動できないので Gradleプロジェクトに変換してあげる。

③プロジェクトを右クリック→構成→Gradle ネーチャーの追加

f:id:Tokuty:20201115215327p:plain

後はいつもどおりSpringアプリケーションとして起動してあげればOK

用語

インポート・・・取り込む 他のソフトで作成されたデータやファイルを読み込んで利用できるようにすること。
エクスポート・・・書き出し 他のソフトが読み込めるように変換したり、そのような形式でファイルを保存すること。
Gradleネーチャーの追加・・・Eclipseの既存プロジェクトをGradleプロジェクトに変換すること。 

Exceptionクラスについて①

他の方が担当していた再現できないエラーのため問題なしとして処理されてしまった不具合をもう一度調査してくださいと言われた時の話です。
手順などは詳しく書いておらず、画像の添付とログがあったので画像通りの条件で実行してみましたが確かに再現できませんでした。
不思議に思って添付されていた実行ログを見るとExcptionエラーが出ていたため調査してみました。
ArgumentOutOfRangeException : 引数の値が、呼び出されたメソッドで定義されている許容範囲外である場合にスローされる例外。

例としてはこんな感じ。

Progam.cs

var list = new List<string> { "A", "B", "C" }; // ①
Console.WriteLine(list[0]);

var emptyList = list.Where(e => string.IsNullOrEmpty(e)).ToList();  // ②
Console.WriteLine(emptyList[0]);

List<string> A = null; // ③
Console.WriteLine(A[0]);

①はリストの宣言と格納を同時に行い一つ目のリストの情報を取り出して表示させるようなプログラム。

②は①のリストからNullもしくは値が空のものをemptyListに詰めてあげる。そのためリストの中身は空になります。 その状態で[0]で一つ目のリストの情報を取り出しているため、ArgumentOutOfRangeException が発生します。

③はリストにnullを入れたあとに[0]で一つ目のリストの情報を取り出しているためNullReferenceExceptionが発生します。

感想

実際のコードはDBからテーブルのレコードを検索して、結果がない場合に[0]で参照しているため100%落ちるようなプログラムでしたが、 nullの時確実に落ちるため、非常に危険なコードでした。。。 今回の事での学びですが、Exceptionエラーについて詳しくなると何が悪いのか?がわかってくるので大事ですね! 後、手順通りできなくても問題なしと判断するのではなくじっくり検証する必要があることがよくわかりました。

Jquery .empty()

Jqueryの.empty()についてですが、 こちらのメソッドは要素を削除するとても便利なメソッドとなっております。 だけど何も考えずに使うとめんどくさいことに。。。 何かしらを検索してエラーがあった場合画面に戻り、エラーメッセージが表示されるような処理があるとします。 そしてClearボタンを押すことでエラーメッセージを削除するような機能があるとします。 例えばこんな感じ。検索等は省略させて頂いてます。

AddMessageでリストにmessageを追加した後にClearを押すことで要素を消去しています。 消去した後にAddMessageを押しますが何も追加されません。。 以下ソースコードです。

f:id:Tokuty:20201029214333g:plain

index.html

<body>
    <div class="msg_err_list">
        <ul>
            <li>err_message</li>
        </ul>
    </div>
    <button id="clear">clear</button>
    <button id="add">AddMessage</button>
    <script src="index.js"></script>
</body>

index.js

$('#clear').on('click', function () {
    $('.msg_err_list').empty();
});

$('#add').on('click', function () {
    $('ul').append('<li>err_message</li>');
});

どうやらclass="msg_err_list"直下全ての子要素を消去してしまったためメッセージが追加されなくなってしまったようです。。 解決策としてempty()で削除した後にもう一度<ul><li></li></ul>を追加してみましょう。

index.js 修正

$('#clear').on('click', function () {
    $('.msg_err_list').empty();
    $('.msg_err_list').append('<ul><li>err_message</li></ul>');
});

$('#add').on('click', function () {
    $('ul').append('<li>err_message</li>');
});

f:id:Tokuty:20201029220107g:plain

上手くいきました! 便利なメソッドですが、何も考えずに実装しちゃうとこうなります。 考えて使いましょう!

onclickイベントの動作

ドロップダウンリストから数値を選択して、"2"の場合は非活性にする機能があるとします。 oncick()イベントはクリックした時に起こるイベントのため、 選択中に別の場所をクリックすると動画のような不具合が起こります。 f:id:Tokuty:20201028215557g:plain

以下実装コード

html 修正前

    <form>
        <select id="list_box" onclick="func()" name="num">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
        </select>
        <input type="submit" value="送信">
    </form>

js

function func() {
    const list_box = document.getElementById('list_box');
    if (list_box.value === "2") {
        list_box.disabled = true;
    }
}

選択時のイベントが正しいためonchangeイベントに変更すると問題なく動作しました。

html 修正後

    <form>
        <select id="list_box" onchange="func()" name="num">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
        </select>
        <input type="submit" value="送信">
    </form>

イベントの動作タイミングをよく考えて実装しないとだめですね。。 ちなみにIEだと非活性状態のボタンをクリックするとonclickが呼ばれちゃったりするので注意。

linqでグループ化

最初に

現場でGroupByを使用することが増えてきたので復習のためにやってみます!

やり方は先輩エンジニアの方に教えてもらいました。

簡単に説明すると、カラムをグルーピングすることで、テーブルがぐしゃっとなるらしいですw うーん。。。難しい!!

sqlの知識があまりなく、理解が追いつかなかったので、今回はsqlコマンドを使いながら結果を比べながらやっていきたいと思います。

まずはやることから。

使用している体育館の総数を調べます。

テーブルは前回のテーブル結合で使用したPesonとTeamを使っていきます。

Model

Team.cs

public int Sum { get; set; }

groupingした体育館の総数を入れるSumを追加。

Controller

PeopleController.cs

前回内部結合したPTQueryを使用

var PTGroup = PTQuery.GroupBy(pt => new { pt.Team.HeadQuarterName})

                                       .Select(pt => new PTHDto { HeadQuarterName =                                                                                        pt.Key.HeadQuarterName, Sum = pt.Count() });

GroupByでグルーピングしたいカラム名を決める。

SelectでDBから取得したいカラム名を決める。

sql文を確認しながらやるとわかりやすいです。

結果表示

f:id:Tokuty:20200208142912p:plain

Sql

sql

SELECT * FROM Person INNER JOIN Team ON Person.TeamName = Team.TeamName;

f:id:Tokuty:20200208145400p:plain

内部結合

sql

SELECT *, COUNT(HeadQuarterName) FROM

Person INNER JOIN Team ON Person.TeamName = Team.TeamName

GROUP BY HeadQuarterName;

f:id:Tokuty:20200208145415p:plain

内部結合→グループ化

なるほど・・・ぐちゃっとなってますねw