【Java備忘録】StreamAPIをつかったListのフィルタリング

はじめに

RDB(リレーショナルデータベース) において SQL で AND条件で検索するような感じで、
Map<項目名,値> に設定した条件で、List< Map<項目名,値>> の内容をフィルタリングする例です。

フィルタリング方法

抽出対象のレコードを stream の filter で 絞り込み、Collectors.toList で新たなリストに集約します。
filter内では、Mapエントリを stream の allMatch (=AND条件なので) で 条件の値比較をします。

List< Map<String, Object> > result = 《抽出対象のレコード》.stream().filter(
            row -> 《抽出条件のマップ》.entrySet().stream().allMatch( map -> 《row.get( map.getKey() ) と map.getValue() を比較しOK なら true を返却する式》 ) ).collect( Collectors.toList() );

以下のような場合に使えるかもしれません。

  • フィルタリング対象のレコードが数万件にならないデータを RDB を介したくない場合
  • 条件のみ入れ替えて都度データ抽出が必要な場合

テストデータ・テスト結果もこみ込みで、ソースコードを書いています。参考にしてください。

import java.util.List;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Map;
import java.util.Random;
import java.util.HashMap;
import java.util.stream.Collectors;

class filterTest {
    public static void main(String args[]) {
        //フィルタリング対象のデータをセット
        List< Map<String, Object> > rows = setTestData();
        //フィルタリングする値
        Map< String, Object > filterMap =  new HashMap<>();
        filterMap.put( "value1", "A" );
        filterMap.put( "value2", Integer.valueOf( 1 ) );

        System.out.println("フィルタリング前の出力 -----");
        //フィルタリング前の出力
        rows.stream().forEach(row -> System.out.println( MessageFormat.format( "key= {0} (value1= {1}, value2= {2})", row.get("key"), row.get("value1"), row.get("value2"))));
        System.out.println("フィルタリング後の出力 -----");
        //フィルタリング処理
        List< Map<String, Object> > result = rows.stream().filter(
            row -> filterMap.entrySet().stream().allMatch( map -> equals( row.get( map.getKey() ), map.getValue() ) )
        ).collect( Collectors.toList() );
        //フィルタリング結果の出力
        result.stream().forEach(row -> System.out.println( MessageFormat.format( "key= {0} (value1= {1}, value2= {2})", row.get("key"), row.get("value1"), row.get("value2"))));
    }
    /**
     * テストデータの設定( key,val1,val2 カラムで構成されるRDBテーブルレコードを想定)
     *   key : String, value1 : String, value2 : Integer
     * @return テストデータリスト
     */
    public static List<Map<String, Object>> setTestData() {
        //オブジェクトの初期化
        List< Map<String, Object> > rows = new ArrayList< Map<String, Object> >();
        Random random = new Random();
        //1000件分のテストデータを作成する
        for(int i = 0; i < 1000; i++) {
            Map<String, Object> row = new HashMap<String, Object>();
            row.put("key", String.valueOf(i + 1));
            row.put("value1", new String(Character.toChars(random.nextInt( 26 ) + 65)) );
            row.put("value2", random.nextInt( 10 ) );
            rows.add(row);
        }
        return rows;
    }

    private static boolean equals( final Object obj1, final Object obj2 ) {
        if ( obj1 != null ) return obj1.equals( obj2 );
        if ( obj2 != null ) return obj2.equals( obj1 );
        return true;
    }
}
タイトルとURLをコピーしました