プログラマ38の日記

主にプログラムメモです。

Java: いまさらになってStream APIをさわってみた

今さらですが、java8で追加されたStream APIをさわってみました。

自分でコードを書く際には使いませんが、別の人のコードを読むときや、Stream APIを使って書かれたコードを修正する時には知ってたほうがいいかなーと思っていて、ざっくりと理解しようとした時のメモです。

※なので、全てを把握してはいません。

 

  • リスト、マップを便利に使える仕組み、forを使って色々処理していることをメソッドとしてコードが書ける
  • メソッドには、各要素に対して操作するもの、要素全体に対して操作するものがある

 

forで定型的なプログラムを書く手間を省くための仕組みだと理解しました。

よくあるリストを使った処理を想定してかき分けてみたいと思います。

 

処理1:

リストの要素をSQLの in の検索条件として使う

    

//このリストを検索条件にしたい

List<String> searchlist = Arrays.asList("レキシ","B'z","サカナクション");





//streamを使った場合

String searchstr = searchlist.stream()

         .map(s-> "'" + s.replaceAll("'", "''") + "'")

         .collect(Collectors.joining(", ", "searchfield in (", ")"));







//今まで通りのfor文を使った場合

StringJoiner tempjoiner = new StringJoiner(", ", "searchfield in (", ")");

for(String s : searchlist) {

    tempjoiner.add("'" + s.replaceAll("'", "''") + "'");

}
String searchstr2 = tempjoiner.toString();

どちらで書いても「searchfield in ('レキシ', 'B''z', 'サカナクション')」の、SQLのWhere句の文字列となります。

上記のポイントとしてシングルクオートはエスケープしています。値の中にシングルクオートを持つ名詞を探したらB'zを見つけたので、ミュージシャンでリストを作成してみました。

streamを使っても使わなくてもあまり変わらないように思います。StringJoinerを使ってるせいかもしれませんが。

 

処理2:

リストの要素をフィルタして別のリストを作る

// 事前準備 start ********************************** 

//こんなクラスを用意

public class UserInfo {

    String username;

    boolean isActive;

    

    public UserInfo(String username, boolean isActive) {

        this.username = username;

        this.isActive = isActive;

    }

}



//こんなリストを用意

UserInfo u1 = new UserInfo("A", true);

UserInfo u2 = new UserInfo("B", false);

UserInfo u3 = new UserInfo("C", true);



List<UserInfo> users = Arrays.asList(u1,u2,u3);

// 事前準備 end  ********************************** 





//streamを使った書き方

List<UserInfo> activeUsers = users.stream()

        .filter(u-> u.isActive == true)

        .collect(Collectors.toList());

List<UserInfo> inactiveUsers = users.stream()

        .filter(u-> u.isActive == false)

        .collect(Collectors.toList());





//for文を使った書き方

List<UserInfo> activeUsersF = new ArrayList<>();

List<UserInfo> inactiveUsersF = new ArrayList<>();



for(UserInfo u : users) {

    if( u.isActive == true ) activeUsersF.add(u);

    if( u.isActive == false ) inactiveUsersF.add(u);                

}    

プログラムでこういうフィルタがしたいということが明確で、streamだとわかりやすさがあります。

 

最後に

上記のメモでは、Streamのmap, collect, filterメソッドだけを使っていますが、Streamにはたくさんのメソッドが用意されていて、例えば、ソート用のsorted、それぞれの要素で処理を行うforEachなどがあります。

さらにcollectメソッドで使うCollectorsクラスには、返却するリストやマップ、文字列をさらに細かく指定できるメソッドが用意されています。StreamとCollectorsを抑えればStream APIで困ることはないかなと考えています。

 

あと、なんでもそうですが、できるからといって技を駆使してプログラムを書くとメンテナンスできないものになります。(perlとかは最たる例だと思います。)

streamは仕様変更には弱そうだなと直感的に感じていて、普通の人が普通にプログラム修正するには癖が強いと思いました。

実際に書く際には、ここまでは利用してここから先は利用しない、もしくはこういった処理だけ利用するなどの線引きが必要だなーと思いました。