利用stream对list集合中的bigdecimal进行分组求和,均值,最大值,最小值
Posted 醉酒的小男人
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用stream对list集合中的bigdecimal进行分组求和,均值,最大值,最小值相关的知识,希望对你有一定的参考价值。
Java8原生只提供了summingInt、summingLong、summingDouble三种基础类型的方法,想要对BigDecimal类型的数据操作需要自己新建工具类如下:
案例代码
简单的方式取值:
BigDecimal totalPrice = list.stream().map(ProductA::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
创建一个函数式接口:
package utils;
import java.math.BigDecimal;
@FunctionalInterface
public interface ToBigDecimalFunction<T> {
BigDecimal applyAsBigDecimal(T value);
}
创建工具类
package utils;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
public class CollectorsUtil {
static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
private CollectorsUtil() {
}
@SuppressWarnings("unchecked")
private static <I, R> Function<I, R> castingIdentity() {
return i -> (R) i;
}
static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
private final Supplier<A> supplier;
private final BiConsumer<A, T> accumulator;
private final BinaryOperator<A> combiner;
private final Function<A, R> finisher;
private final Set<Characteristics> characteristics;
CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
Function<A, R> finisher, Set<Characteristics> characteristics) {
this.supplier = supplier;
this.accumulator = accumulator;
this.combiner = combiner;
this.finisher = finisher;
this.characteristics = characteristics;
}
CollectorImpl(Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, castingIdentity(), characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}
//求和方法
public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(ToBigDecimalFunction<? super T> mapper) {
return new CollectorImpl<>(
() -> new BigDecimal[]{BigDecimal.ZERO},
(a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); },
(a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
a -> a[0], CH_NOID);
}
//求最大值
public static <T> Collector<T, ?, BigDecimal> maxBy(ToBigDecimalFunction<? super T> mapper) {
return new CollectorImpl<>(
() -> new BigDecimal[]{new BigDecimal(Long.MIN_VALUE)},
(a, t) -> { a[0] = a[0].max(mapper.applyAsBigDecimal(t)); },
(a, b) -> { a[0] = a[0].max(b[0]) ; return a; },
a -> a[0], CH_NOID);
}
//求最小值
public static <T> Collector<T, ?, BigDecimal> minBy(ToBigDecimalFunction<? super T> mapper) {
return new CollectorImpl<>(
() -> new BigDecimal[]{new BigDecimal(Long.MAX_VALUE)},
(a, t) -> { a[0] = a[0].min(mapper.applyAsBigDecimal(t)); },
(a, b) -> { a[0] = a[0].min(b[0]) ; return a; },
a -> a[0], CH_NOID);
}
/**
* 求平均值
* @param mapper
* @param newScale 保留newScale位小数
* @param roundingMode 舍去规则(0 <= roundingMode <= 7)
* @param <T>
* @return
*/
public static <T> Collector<T, ?, BigDecimal> averagingBigDecimal(ToBigDecimalFunction<? super T> mapper, int newScale, int roundingMode) {
return new CollectorImpl<>(
() -> new BigDecimal[]{BigDecimal.ZERO,BigDecimal.ZERO},
(a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); a[1] = a[1].add(BigDecimal.ONE); },
(a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
a -> a[0].divide(a[1],BigDecimal.ROUND_HALF_UP).setScale(newScale, roundingMode), CH_NOID);
}
}
创建Student类:
package utils;
import java.math.BigDecimal;
public class Student {
private Integer id;
private String sex;
private Integer age;
private BigDecimal score;
public Student(Integer id,String sex, Integer age, BigDecimal score) {
this.id = id;
this.sex = sex;
this.age = age;
this.score = score;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public BigDecimal getScore() {
return score;
}
public void setScore(BigDecimal score) {
this.score = score;
}
}
测试类
package utils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class StreamTest {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student(1,"男",18,new BigDecimal(100)));
list.add(new Student(2,"男",19,new BigDecimal(90)));
list.add(new Student(3,"女",20,new BigDecimal(80)));
list.add(new Student(4,"女",20,new BigDecimal(70)));
list.add(new Student(5,"女",20,null));
//单条件筛选
//按照性别分组求分数总和
Map<String, BigDecimal> scoreCount = list.stream().filter(t -> t.getScore() != null).collect(Collectors.groupingBy(Student::getSex, CollectorsUtil.summingBigDecimal(Student::getScore)));
System.out.println("----按照性别分组求分数总和----");
scoreCount.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
//按照性别求分数平均值
Map<String, BigDecimal> scoreAvg = list.stream().filter(t -> t.getScore() != null).collect(Collectors.groupingBy(Student::getSex, CollectorsUtil.averagingBigDecimal(Student::getScore,2,0)));
System.out.println("----按照性别求分数平均值----");
scoreAvg.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
//按照性别年龄分组求分数总和
Map<String, BigDecimal> ageScoreCount = list.stream().filter(t -> t.getScore() != null).collect(Collectors.groupingBy(p -> fetchGroupKey(p), CollectorsUtil.summingBigDecimal(Student::getScore)));
System.out.println("----按照性别年龄分组求分数总和----");
ageScoreCount.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
//按照性别年龄分组求分数平均值
Map<String, BigDecimal> ageScoreAvg = list.stream().filter(t -> t.getScore() != null).collect(Collectors.groupingBy(p -> fetchGroupKey(p), CollectorsUtil.averagingBigDecimal(Student::getScore,2,1)));
System.out.println("----按照性别年龄分组求分数平均值----");
ageScoreAvg.forEach((k,v) -> System.out.println("key: " + k + " , " + "value: " + v));
}
//多条件筛选
//多条件筛选分组属性
private static String fetchGroupKey(Student stu) {
return stu.getAge() + "#" + stu.getSex();
}
}
执行结果
BigDecimal.setScale用法
BigDecimal.setScale(int newScale, int roundingMode)
newScale: 保留newScale位小数
roundingMode: 舍去规则(0 <= roundingMode <= 7)
一、BigDecimal.ROUND_UP=0
BigDecimal num = new BigDecimal("3.161590");
// 进位处理,不进行四舍五入(精度后的位数是0不进位)
System.out.println(num.setScale(1, BigDecimal.ROUND_UP)); // 3.2
System.out.println(num.setScale(2, BigDecimal.ROUND_UP)); // 3.17
System.out.println(num.setScale(5, BigDecimal.ROUND_UP)); // 3.16159
二、BigDecimal.ROUND_DOWN=1
BigDecimal num = new BigDecimal("3.16159");
// 直接舍去多余的位数,不进行四舍五入
System.out.println(num.setScale(1, BigDecimal.ROUND_DOWN)); // 3.1
System.out.println(num.setScale(2, BigDecimal.ROUND_DOWN)); // 3.16
三、BigDecimal.ROUND_CEILING=2
BigDecimal num = new BigDecimal("3.161590");
// 天花板(向上),正数进位向上,同ROUND_UP
System.out.println(num.setScale(1, BigDecimal.ROUND_CEILING)); // 3.2
System.out.println(num.setScale(2, BigDecimal.ROUND_CEILING)); // 3.17
System.out.println(num.setScale(5, BigDecimal.ROUND_CEILING)); // 3.16159
BigDecimal num = new BigDecimal("-3.161590");
// 天花板(向上),负数舍位向上,同ROUND_DOWN
System.out.println(num.setScale(1, BigDecimal.ROUND_CEILING)); // -3.1
System.out.println(num.setScale(2, BigDecimal.ROUND_CEILING)); // -3.16
System.out.println(num.setScale(5, BigDecimal.ROUND_CEILING)); // -3.16159
四、BigDecimal.ROUND_FLOOR=3
BigDecimal num = new BigDecimal("3.161590");
// 地板(向下),正数舍位向下
System.out.println(num.setScale(1, BigDecimal.ROUND_FLOOR)); // 3.1
System.out.println(num.setScale(2, BigDecimal.ROUND_FLOOR)); // 3.16
BigDecimal num = new BigDecimal("-3.161590");
// 地板(向下),负数进位向下
System.out.println(num.setScale(1, BigDecimal.ROUND_FLOOR)); // -3.2
System.out.println(num.setScale(2, BigDecimal.ROUND_FLOOR)); // -3.17
五、 BigDecimal.ROUND_HALF_UP=4
BigDecimal num = new BigDecimal("3.161590");
// 正常四舍五入
System.out.println(num.setScale(1, BigDecimal.ROUND_HALF_UP)); // 3.2
System.out.println(num.setScale(2, BigDecimal.ROUND_HALF_UP)); // 3.16
六、BigDecimal.ROUND_HALF_DOWN=5
BigDecimal num = new BigDecimal("3.161500");
// 四舍五入(若舍弃部分>.5,就进位)
System.out.println(num.setScale(1, BigDecimal.ROUND_HALF_DOWN)); // 3.2
System.out.println(num.setScale(2, BigDecimal.ROUND_HALF_DOWN)); // 3.16
System.out.println(num.setScale(3, BigDecimal.ROUND_HALF_DOWN)); // 3.161
num = new BigDecimal("3.161590");
// .590 > .5
System.out.println(num.setScale(3, BigDecimal.ROUND_HALF_DOWN)); // 3.162
七、BigDecimal.ROUND_HALF_EVEN=6
BigDecimal num = new BigDecimal("3.46159");
// 如果舍弃部分左边的数字为偶数,则作 ROUND_HALF_DOWN
System.out.println(num.setScale(1, BigDecimal.ROUND_HALF_EVEN)); // 3.5
System.out.println(num.setScale(2, BigDecimal.ROUND_HALF_EVEN)); // 3.46
BigDecimal num = new BigDecimal("3.37459");
// 如果舍弃部分左边的数字为奇数,则作 ROUND_HALF_UP
System.out.println(num.setScale(1, BigDecimal.ROUND_HALF_EVEN)); // 3.4
System.out.println(num.setScale(2, BigDecimal.ROUND_HALF_EVEN)); // 3.37
八、BigDecimal.ROUND_UNNECESSARY=7
BigDecimal num = new BigDecimal("3.37459");
// 断言请求的操作具有精确的结果
System.out.println(num.setScale(5, BigDecimal.ROUND_UNNECESSARY)); // 3.37459
System.out.println(num.setScale(2, BigDecimal.ROUND_UNNECESSARY)); // 抛出ArithmeticException
如果有5位小数,那么指定舍5位的话,会正确输出结果。但是指定的位数不是num的位数,即不是5位,那么会抛出ArithmeticException异常,这样就可以检证num的小数位数。
以上是关于利用stream对list集合中的bigdecimal进行分组求和,均值,最大值,最小值的主要内容,如果未能解决你的问题,请参考以下文章