目的:学習したことの整理・アウトプット
今回扱うクラスの処理の目的:Readerメソッドで取得した情報をユーザーごとに分けて請求額を計算(Readerで得た情報の処理)
流れ
ユーザーごとに(UserIdで)に請求情報をまとめて管理
⇩
全部の請求(finalPaymentAmount)をリストから取り出す
⇩
支払方法に応じて、請求金額の合計を計算
⇩
請求額の合計をアウトプット(Writerメソッドへ)
ItemProcessorの処理全体
※個別の処理の解説は下へ
@Bean
public ItemProcessor<List<BillingRecord>, List<UserTotalBilledAmount>> processor() {
return billingRecords -> {
// ユーザーごとに請求記録をグループ化
Map<Integer, List<BillingRecord>> groupedByUser = billingRecords.stream()
.collect(Collectors.groupingBy(BillingRecord::getUserId));
// 結果リストの準備
List<UserTotalBilledAmount> results = new ArrayList<>();
// グループごとに処理
for (Map.Entry<Integer, List<BillingRecord>> entry : groupedByUser.entrySet()) {
// ユーザー情報の取得
int userId = entry.getKey();
String userName = entry.getValue().get(0).getUserName();
String creditCardNumber = entry.getValue().get(0).getCreditCardNumber();
// 請求金額の合計を計算
double totalAmount = 0.0;
for (BillingRecord record : entry.getValue()) {
double amount = record.getFinalPaymentAmount();
switch (record.getPaymentId()) {
case 1:
totalAmount += amount; // 全額加算
break;
case 6:
totalAmount += amount / 6; // 6分の1を加算
break;
case 12:
totalAmount += amount / 12; // 12分の1を加算
break;
default:
totalAmount += 0; // 何もしない
break;
}
}
// 結果オブジェクトを作成してリストに追加
UserTotalBilledAmount userTotal = new UserTotalBilledAmount(userId, userName, creditCardNumber, totalAmount);
results.add(userTotal);
}
// 結果を返却
return results;
};
}
やりたいこと(目的)と手段
目的1
ユーザーごとに請求情報一覧をまとめたい。
⇩ 言い換えると、、
ユーザーIdとその請求額をセットでまとめたい。
Map<Integer, List<BillingRecord>> groupedByUser = billingRecords.stream()
.collect(Collectors.groupingBy(BillingRecord::getUserId));
手段(抽象度_高)
1. Mapで管理する
2. コレクションの種類を変換する
※処理順番は2.=>1.
手段(具体度_高)
- **.stream()**を使用してコレクション生成
- コレクションに対して、groupingByメソッドでカテゴリー分け&ユーザーIdと請求情報の紐づけ
参考
Stream APIの基本
groupingByメソッドの使い方
ラムダ式の使い方
目的2
マップからキーと値を取りだし、ユーザーId、ユーザー名、クレジットカード番号、当該月の請求額合計をセットで管理したい。
List<UserTotalBilledAmount> results = new ArrayList<>();
for (Map.Entry<Integer, List<BillingRecord>> entry : groupedByUser.entrySet()) {
int userId = entry.getKey();
String userName = entry.getValue().get(0).getUserName();
String creditCardNumber = entry.getValue().get(0).getCreditCardNumber();
(中略)
UserTotalBilledAmount userTotal = new UserTotalBilledAmount(userId, userName, creditCardNumber, totalAmount);
results.add(userTotal);
}
return results;
手段(抽象度_高)
- 上記4項目を保持するオブジェクトを格納するためのリストを用意
- Mapから4項目を取得
マップに含まれるキーと値のマッピングのセットを取得する - 請求額合計を支払い方法に応じて合計・計算(中略部分)
- 「1.」で作成したリストへ格納
- 「4.」のリストを出力
手段(具体度_高)
- 略
- Mapから4項目を取得
entrySet()メソッドと拡張forを利用してキーと値のセットを取得する
Ⅰ.ユーザーId = キーなので getKey()メソッドで取得
Ⅱ.ユーザー名とクレジットカード番号は、 getValue().get(0).getフィールド名()メソッドで取得
※ユーザーIdでグループ化した請求情報リスト内のユーザー名とクレカ番号は、同じユーザーに属するため、get(0)でリストの先頭を指定すればよい - 省略
- インスタンス化&フィールド変数をセット
- addメソッドでリストへ追加
参考
拡張for文を利用したMapのキーと値の取得
Mapで使用する主要メソッド
Iteratorとは
目的3
支払方法に応じて当月の請求を計算する。(1,6,12回払いの3種類)
switch (record.getPaymentId()) {
case 1:
totalAmount += amount; // 全額加算
break;
case 6:
totalAmount += amount / 6; // 6分の1を加算
break;
case 12:
totalAmount += amount / 12; // 12分の1を加算
break;
default:
totalAmount += 0; // 何もしない
break;
}
特定のデータの値パターンをチェックしたい場合は「switch文」を使う。
基本は条件分岐はIf文で対応すべきだが、場合によってはswitch文の方が可読性が高くなる
参考
https://java-code.jp/1501
https://enterprisegeeks.hatenablog.com/entry/2014/06/19/093000#:~:text=partitioningBy%2C%20groupingBy,%22%20%3D%20%22%20%2B%20v%3B
https://en-ambi.com/itcontents/entry/2019/04/25/103000/#%E3%83%A9%E3%83%A0%E3%83%80%E5%BC%8F%E3%81%AE%E5%9F%BA%E6%9C%AC:~:text=%E3%81%84%E3%82%8B%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%80%82-,List%3CInteger%3E%20numbers%20%3D%20List.of(3%2C%201%2C%20%2D4%2C%201%2C%20%2D5%2C%209%2C%20%2D2%2C%206%2C%205%2C%203%2C%205)%3B%0Anumbers.stream()%0A%20%20%20%20%20%20%20%20.filter(number%20%2D%3E%20Math.abs(number)%20%3E%3D%205)%0A%20%20%20%20%20%20%20%20.forEach(System.out%3A%3Aprintln)%3B,-%E5%BC%95%E6%95%B0%E3%81%AE%E5%80%A4
https://www.techiedelight.com/ja/iterate-map-in-java-using-entryset/#google_vignette
https://dtnavi.tcdigital.jp/cat_web/web_015/
https://workteria.forward-soft.co.jp/blog/detail/10082