1
0

More than 3 years have passed since last update.

レスポンスデータを加工する(Stream)

Posted at

※前回記事レスポンスデータを加工する(拡張for文)のStream版です。
違いだけを知りたい人は「データを加工」までジャンプしてください。

はじめに

レスポンスデータって全要素使うわけではなかったり、ネスト構造になってたり、結構見にくいことが多いと思います。
ということで取得したレスポンスを加工(フィルター, マッピング, ソート)して、自分好みのデータクラスを作成してみました。

ゴール

フィルター(抽出):likeCountが5より大きいもの
マッピング(結合):title,body,likeCount,name
ソート(並び替え):likeCountで降順

加工前 加工後
スクリーンショット 2021-03-16 22.02.13.png

実装

※コード長くなるため、API使わずにレスポンスを模した自作の簡易データを使ってます。

加工前データクラス定義

使用しないゲッター、セッターは省略してます

ArticleResponse.java
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;
    }
}
User.java
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;
    }
}

加工データクラス定義

使用しないゲッター、セッターは省略してます

ArticleBusinessModel.java
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が使えないため

AndroidManifest.xml
<uses-sdk android:minSdkVersion="24" />

データを加工

ArticleRepository.java
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

非常にわかりやすかったです。ありがとうございました!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0