※前回記事レスポンスデータを加工する(拡張for文)のStream版です。
違いだけを知りたい人は「データを加工」までジャンプしてください。
はじめに
レスポンスデータって全要素使うわけではなかったり、ネスト構造になってたり、結構見にくいことが多いと思います。
ということで取得したレスポンスを加工(フィルター, マッピング, ソート)して、自分好みのデータクラスを作成してみました。
ゴール
フィルター(抽出):likeCountが5より大きいもの
マッピング(結合):title,body,likeCount,name
ソート(並び替え):likeCountで降順
加工前 | 加工後 |
---|---|
実装
※コード長くなるため、API使わずにレスポンスを模した自作の簡易データを使ってます。
加工前データクラス定義
使用しないゲッター、セッターは省略してます
public class ArticleResponse {
private String title;
private String body;
private String createdAt;
private int likeCount;
private User user;
public ArticleResponse(String title, String body, String createdAt, int likeCount, User user) {
this.title = title;
this.body = body;
this.createdAt = createdAt;
this.likeCount = likeCount;
this.user = user;
}
public String getTitle() {
return title;
}
public String getBody() {
return body;
}
public int getLikeCount() {
return likeCount;
}
public User getUser() {
return user;
}
}
public class User {
private String name;
private int id;
private int followeesCount;
private int followersCount;
public User(String name, int id, int followeesCount, int followersCount) {
this.name = name;
this.id = id;
this.followeesCount = followeesCount;
this.followersCount = followersCount;
}
public String getName() {
return name;
}
}
加工データクラス定義
使用しないゲッター、セッターは省略してます
public class ArticleBusinessModel {
private String title;
private String body;
private int likeCount;
private String name;
public ArticleBusinessModel(String title, String body, int likeCount, String name) {
this.title = title;
this.body = body;
this.likeCount = likeCount;
this.name = name;
}
public int getLikeCount() {
return likeCount;
}
}
android:minSdkVersionの設定
バージョン24以上でないとStreamが使えないため
<uses-sdk android:minSdkVersion="24" />
データを加工
public class ArticleRepository {
private ArrayList<ArticleResponse> responses = sampleResponseData(); // 加工前のサンプルデータ
public List<ArticleBusinessModel> mapping() {
List<ArticleBusinessModel> processedData = responses.stream()
.filter(article -> article.getLikeCount() > 5)
.map(article -> new ArticleBusinessModel(
article.getTitle(),
article.getBody(),
article.getLikeCount(),
article.getUser().getName())
)
.sorted(Comparator.comparing(ArticleBusinessModel::getLikeCount).reversed())
.collect(Collectors.toList());
// 中身見るためにJsonに変換
Gson gson = new Gson();
Log.i("元データ:", gson.toJson(responses));
Log.i("加工データ:", gson.toJson(processedData));
return processedData;
}
// サンプルデータ作成
private ArrayList<ArticleResponse> sampleResponseData() {
ArrayList<ArticleResponse> dataList = new ArrayList<>();
User user1 = new User("Ichiro", 1, 70, 50);
User user2 = new User("Jiro", 2, 40, 10);
User user3 = new User("Saburo", 3, 20, 5);
User user4 = new User("Shiro", 4, 10, 5);
dataList.add(new ArticleResponse("Java", "静的型付け言語です", "2021/3/1", 10, user1));
dataList.add(new ArticleResponse("Ruby", "動的型付け言語です", "2021/3/2", 8, user2));
dataList.add(new ArticleResponse("Swift", "静的型付け言語です", "2021/3/2",14, user3));
dataList.add(new ArticleResponse("NoCode", "ノーコードです", "2021/3/3", 3, user4));
return dataList;
}
}
※データ加工の呼び出し処理は割愛。ViewModelとかで呼び出してみてください。
コード解説
Streamの使い方
stream,中間操作,終端操作の順でデータを加工していく。
[ stream ] 加工したいデータをStream化する
・ stream()
Stream型に変換する
↓
[ 中間操作 ] データを加工する
・ filter()
指定された条件を満たすもののみを抽出する
・ map()
Streamの各要素を別の要素に型変換する
・ sorted()
指定した要素を基準にして並び替える
↓
[ 終端操作 ] 結果を得る
・ collect()
Stream処理の解説
// memo: private ArrayList<ArticleResponse> responses = sampleResponseData();
// [ stream ]
// List<ArticleResponse> → Stream<ArticleResponse> に変換
List<ArticleBusinessModel> processedData = responses.stream()
// [ 中間操作 ]
// ArticleResponseのStream内の各要素から取り出したlikeCountの中から、
// 条件に合うものだけを抽出
.filter(article -> article.getLikeCount() > 5) // article(任意名)の型名を省略できる
// ArticleResponseのStream内の各要素から必要な値を取り出して、
// Stream<ArticleResponse> → Stream<ArticleBusinessModel> に変換
.map(article -> new ArticleBusinessModel(
article.getTitle(),
article.getBody(),
article.getLikeCount(),
article.getUser().getName())
)
// ArticleBusinessModelのStream内の各要素から取り出したlikeCountをもとに並び替え
.sorted(Comparator.comparing(ArticleBusinessModel::getLikeCount).reversed())
// [ 終端操作 ]
// Stream<ArticleBusinessModel> → List<ArticleBusinessModel> に変換
.collect(Collectors.toList());
【比較してみる】 Streamを使わない場合
List<ArticleBusinessModel> processedData = new ArrayList<ArticleBusinessModel>();
for (ArticleResponse article : responses) {
if (article.getLikeCount() > 5) {
processedData.add(new ArticleBusinessModel(
article.getTitle(),
article.getBody(),
article.getLikeCount(),
article.getUser().getName())
);
}
}
processedData.sort(Comparator.comparing(ArticleBusinessModel::getLikeCount).reversed());
【比較してみる】 Streamを使った場合
List<ArticleBusinessModel> processedData = responses.stream()
.filter(article -> article.getLikeCount() > 5)
.map(article -> new ArticleBusinessModel(
article.getTitle(),
article.getBody(),
article.getLikeCount(),
article.getUser().getName())
)
.sorted(Comparator.comparing(ArticleBusinessModel::getLikeCount).reversed())
.collect(Collectors.toList());
Streamを使ったほうがスマート!!
参考URL
https://qiita.com/pebblip/items/76a5ecac09335770154b
https://qiita.com/munieru_jp/items/6c0dbada463e00429fd1
https://www.unitrust.co.jp/8367
http://enterprisegeeks.hatenablog.com/entry/2015/11/30/081118
非常にわかりやすかったです。ありがとうございました!