Use of Java 8 Lambdas with Generics

后端 未结 4 1809
执念已碎
执念已碎 2021-02-10 14:37

Is it possible to do this using Predicate interface.

I have a client class that utilizes functions provided by a MathUtility class. Whatever the Mathmatical operation it

4条回答
  •  自闭症患者
    2021-02-10 14:54

    1. you must point out which actual type of Number to be summed, Since the Number class has no static sum method.
    2. you must assign identity with type of T extends Number,0 is an concrete type of Integer and does not compatible with type of T.

    Possible Solution

    you can make which actual type of Number to be summed later, for example:

    Integer sumToInt = MathUtility.sum(numbers, condition).as(Integer.class);
    Double sumToDouble = MathUtility.sum(numbers, condition).as(Double.class);
    

    OR you can make which actual type of Number to be summed ahead, when using this style you are free to take type of actual Number to every sum to be called, one the other hand, you can reuse it without taking any confused parameters and which is exactly what you want,for example:

    SumOp sumIntOp = SumOp.of(Integer.class);
    
    //sumIntOp is reused twice.
    Integer sumToInt1 = sumIntOp.sum(numbers1, condition1);
    Integer sumToInt2 = sumIntOp.sum(numbers2, condition2);
    

    MathUtility

    class MathUtility {
    
        private static  Sum sum(List numbers,
                                                  Predicate condition) {
            return sum(numbers.parallelStream().filter(condition));
        }
    
        private static  Sum sum(Stream stream) {
            return new Sum() {
                public  T as(Class type) {
                    return SumOp.of(type).sum(stream);
                }
            };
        }
    
        interface Sum {
             T as(Class type);
        }
    }
    

    SumOp

    public class SumOp {
        private static final Map, SumOp> OPERATORS = new HashMap<>();
        private final T identity;
        private final BinaryOperator plusOp;
        private final Function valueExtractor;
    
        static {
           register(Integer.class, new SumOp<>(0, Integer::sum, Number::intValue));
           register(Double.class, new SumOp<>(0., Double::sum, Number::doubleValue));
           //todo: add more SumOp for other Number types
        }
    
        public static  void register(Class type,
                                                       SumOp sumOp) {
            OPERATORS.put(type, sumOp);
        }
    
        public static  SumOp of(Class type) {
            return (SumOp) OPERATORS.computeIfAbsent(type, it -> {
                String message = "No SumOp registered for type:" + type.getName();
                throw new IllegalArgumentException(message);
            });
        }
    
        public SumOp(T identity,
                     BinaryOperator plusOp,
                     Function valueExtractor) {
            this.identity = identity;
            this.valueExtractor = valueExtractor;
            this.plusOp = plusOp;
        }
    
        public  T sum(List numbers,
                                        Predicate condition) {
            return sum(numbers.stream().filter(condition));
        }
    
        public T sum(Stream stream) {
            return stream.reduce(identity, this::plus, plusOp);
        }
    
        private T plus(Number augend, Number addend) {
            return plusOp.apply(valueIn(augend), valueIn(addend));
        }
    
        private T valueIn(Number it) {
            return valueExtractor.apply(it);
        }
    }
    

提交回复
热议问题