はじめに
StreamAPIのfilterとreduceのお試し。
以下をEnumとStreamAPIで実装をしてみました。
- 大中小のカテゴリコードを持つマスタがある。
- 大中小を指定して項目を返す。
- 大中配下の小の合計値を返す。
実装
カテゴリマスタ(Enum)
こんな感じで大中小を持つカテゴリマスタを用意します。
Category.java
package com.example.demo.categoryfilter;
public enum Category {
EMPLOYEE_111(1,1,1), // 1部1課 社員1
EMPLOYEE_112(1,1,2), // 1部1課 社員2
EMPLOYEE_113(1,1,3), // 1部1課 社員3
EMPLOYEE_121(1,2,1), // 1部2課 社員1
EMPLOYEE_122(1,2,2), // 1部2課 社員2
EMPLOYEE_123(1,2,3), // 1部2課 社員3
EMPLOYEE_211(2,1,1), // 2部1課 社員1
EMPLOYEE_212(2,1,2), // 2部1課 社員2
;
Category(int large,int medium,int small){
this.large=large;
this.medium=medium;
this.small=small;
}
private int large; // 部コード
private int medium; // 課コード
private int small; // 社員コード
public int getL() {
return large;
}
public void setL(int large) {
this.large = large;
}
public int getM() {
return medium;
}
public void setM(int medium) {
this.medium = medium;
}
public int getS() {
return small;
}
public void setS(int small) {
this.small = small;
}
}
Filterメソッド
CategoryFilter.java
package com.example.demo.categoryfilter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Optional;
public class CategoryFilter {
/**
* 部署と課と社員コードを指定して社員名を返す。
*
* @param list
* @param category
* @return 社員名
*/
public static String filter(List<Employee> list, Category category) {
Optional<String> ret = list.stream()
.filter(e -> e.getL() == category.getL())
.filter(e -> e.getM() == category.getM())
.filter(e -> e.getS() == category.getS())
.map(e -> e.getName())
.findFirst();
return ret.orElse("名無しさん");
}
/**
* 部署と課を指定して配下の社員の給与を合計する。
* BigDecimalの処理はおまけ。
*
* @param list
* @param category
* @return 給与合計
*/
public static BigDecimal sum(List<Employee> list, Category category) {
Optional<BigDecimal> ret = list.stream()
.filter(e -> e.getL() == category.getL())
.filter(e -> e.getM() == category.getM())
.map(e -> e.getSalary())
.reduce((sum, i) -> sum.add(i));
// 初期値0、小数点以下切り捨てで返す
return ret.orElse(BigDecimal.ZERO).setScale(0, RoundingMode.DOWN);
}
}
Employee
Employee.java
package com.example.demo.categoryfilter;
import java.math.BigDecimal;
import lombok.Data;
@Data
public class Employee {
private int l;
private int m;
private int s;
private String name;
private BigDecimal salary;
public Employee(Category category, String name, BigDecimal salary) {
this.l = category.getL();
this.m = category.getM();
this.s = category.getS();
this.name = name;
this.salary = salary;
}
public Employee(Category category, String name, int salary) {
this(category, name, new BigDecimal(salary));
}
}
テストコード
七郎さんと八郎さんは異常系用。
CategoryFilterTests.java
package com.example.demo.categoryfilter;
import static org.hamcrest.CoreMatchers.is;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class CategoryFilterTests {
private static List<Employee> list;
@BeforeClass
public static void before() {
list = sample();
}
@Test
public void test_filter1() {
String name = CategoryFilter.filter(list, Category.EMPLOYEE_123);
System.out.println("EMPLOYEE_123 name=" + name);
Assert.assertThat(name, is("山田六郎"));
}
@Test
public void test_filter2() {
String name = CategoryFilter.filter(list, Category.EMPLOYEE_212);
System.out.println("EMPLOYEE_212 name=" + name);
Assert.assertThat(name, is("名無しさん"));
}
@Test
public void test_sum1() {
BigDecimal sum = CategoryFilter.sum(list, Category.EMPLOYEE_122);
System.out.println("EMPLOYEE_122 sum=" + sum);
Assert.assertThat(sum, is(new BigDecimal(600_000)));
}
@Test
public void test_sum2() {
BigDecimal sum = CategoryFilter.sum(list, Category.EMPLOYEE_212);
System.out.println("EMPLOYEE_21 sum=" + sum);
Assert.assertThat(sum, is(new BigDecimal(0)));
}
private static List<Employee> sample() {
List<Employee> list = new ArrayList<>();
list.add(new Employee(Category.EMPLOYEE_111, "山田一郎", 111_000));
list.add(new Employee(Category.EMPLOYEE_112, "山田二郎", 112_000));
list.add(new Employee(Category.EMPLOYEE_113, "山田三郎", 113_000));
list.add(new Employee(Category.EMPLOYEE_121, "山田四郎", 100_000));
list.add(new Employee(Category.EMPLOYEE_122, "山田五郎", 200_000));
list.add(new Employee(Category.EMPLOYEE_123, "山田六郎", 300_000));
// list.add(new Employee(Category.EMPLOYEE_211, "山田七郎", 211_000));
// list.add(new Employee(Category.EMPLOYEE_212, "山田八郎", 212_000));
list.forEach(System.out::println);
System.out.println();
return list;
}
}
実行結果
ログ
Employee(l=1, m=1, s=1, name=山田一郎, salary=111000)
Employee(l=1, m=1, s=2, name=山田二郎, salary=112000)
Employee(l=1, m=1, s=3, name=山田三郎, salary=113000)
Employee(l=1, m=2, s=1, name=山田四郎, salary=100000)
Employee(l=1, m=2, s=2, name=山田五郎, salary=200000)
Employee(l=1, m=2, s=3, name=山田六郎, salary=300000)
EMPLOYEE_123 name=山田六郎
EMPLOYEE_212 name=名無しさん
EMPLOYEE_122 sum=600000
EMPLOYEE_21 sum=0
あとがき
やっぱりstream apiはキレイですねー。