Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
执行映射缩减操作的通用方法。(Java-8)_Java_Function_Generics_Java 8_Overloading - Fatal编程技术网

执行映射缩减操作的通用方法。(Java-8)

执行映射缩减操作的通用方法。(Java-8),java,function,generics,java-8,overloading,Java,Function,Generics,Java 8,Overloading,在Java8中如何使用泛型参数重载函数 public class Test<T> { List<T> list = new ArrayList<>(); public int sum(Function<T, Integer> function) { return list.stream().map(function).reduce(Integer::sum).get(); } public d

在Java8中如何使用泛型参数重载函数

public class Test<T> {

    List<T> list = new ArrayList<>();

    public int sum(Function<T, Integer> function) {
        return list.stream().map(function).reduce(Integer::sum).get();
    }


    public double sum(Function<T, Double> function) {
        return list.stream().map(function).reduce(Double::sum).get();
    }
}
公共类测试{
列表=新的ArrayList();
公共整数和(函数){
return list.stream().map(function).reduce(Integer::sum).get();
}
公共双和(函数){
return list.stream().map(function).reduce(Double::sum).get();
}
}
错误:java:名称冲突: sum(java.util.function.function)和 sum(java.util.function.function)具有相同的擦除

您需要做的是定义扩展参数类型的自定义函数接口:

public class Test<T> {

    List<T> list = new ArrayList<>();

    @FunctionalInterface
    public interface ToIntFunction extends Function<T, Integer>{}
    public int sum(ToIntegerFunction function) {
        return list.stream().map(function).reduce(Integer::sum).get();
    }


    @FunctionalInterface
    public interface ToDoubleFunction extends Function<T, Double>{}
    public double sum(ToDoubleFunction function) {
        return list.stream().map(function).reduce(Double::sum).get();
    }
}
公共类测试{
列表=新的ArrayList();
@功能接口
函数的公共接口扩展函数{}
公共整数和(ToIntegerFunction){
return list.stream().map(function).reduce(Integer::sum).get();
}
@功能接口
双函数的公共接口扩展函数{}
公共双和(ToDoubleFunction){
return list.stream().map(function).reduce(Double::sum).get();
}
}
另一种方法是使用java.util.function.ToIntFunction和java.util.function.ToDoubleFunction:

public class Test<T> {

    List<T> list = new ArrayList<>();

    @FunctionalInterface
    public int sum(ToIntFunction function) {
        return list.stream().mapToInt(function).sum();
    }

    public double sum(ToDoubleFunction function) {
        return list.stream().mapToDouble(function).sum();
    }
}
公共类测试{
列表=新的ArrayList();
@功能接口
公共整数和(ToIntFunction函数){
返回list.stream().mapToInt(函数).sum();
}
公共双和(ToDoubleFunction){
返回list.stream().mapToDouble(函数).sum();
}
}

您在问题中给出的示例与Java 8无关,而与泛型在Java中的工作方式有关<代码>功能功能和
功能
将在编译时执行,并将转换为
功能
。方法重载的经验法则是具有不同数量、类型或顺序的参数。由于您的两个方法都将转换为接受一个
函数
参数,因此编译器对此表示不满

尽管如此,它已经提供了一种解决问题的方法。该解决方案的问题在于,对于不同类型(整数、双精度等)上的每种类型的操作(加法、减法等),您必须不断修改
Test
类。另一种解决方案是使用
方法重写
而不是
方法重载

测试
等级稍微更改如下:

public abstract class Test<I,O extends Number> {

    List<I> list = new ArrayList<>();

    public O performOperation(Function<I,O> function) {
        return list.stream().map(function).reduce((a,b)->operation(a,b)).get();
    }

    public void add(I i) {
        list.add(i);
    }

    public abstract O operation(O a,O b);
}
public static void main(String []args) {
    Test<String,Integer> test = new MapStringToIntAddtionOperation();
    test.add("1");
    test.add("2");
    System.out.println(test.performOperation(Integer::parseInt));
}
然后,客户端代码可以使用上述代码,如下所示:

public abstract class Test<I,O extends Number> {

    List<I> list = new ArrayList<>();

    public O performOperation(Function<I,O> function) {
        return list.stream().map(function).reduce((a,b)->operation(a,b)).get();
    }

    public void add(I i) {
        list.add(i);
    }

    public abstract O operation(O a,O b);
}
public static void main(String []args) {
    Test<String,Integer> test = new MapStringToIntAddtionOperation();
    test.add("1");
    test.add("2");
    System.out.println(test.performOperation(Integer::parseInt));
}
publicstaticvoidmain(字符串[]args){
Test Test=新的MapStringToIntAdditionOperation();
测试。添加(“1”);
测试。添加(“2”);
System.out.println(test.performOperation(Integer::parseInt));
}
使用这种方法的优点是,您的
测试
类符合
打开-关闭
原则。要添加一个新的运算,如乘法,只需添加一个新的子类
Test
override
两个数字相乘的
运算
方法。将这与模式结合起来,您甚至可以最小化必须创建的子类的数量


注意此答案中的示例仅供参考。有许多方面需要改进(例如使
测试
成为一个功能接口而不是抽象类),这超出了问题的范围。

@srborlongan的解决方案不会很好地工作:)

请参见一个类似的示例-方法-
comparingDouble(ToDoubleFunction)
comparingit(ToIntFunction)
,等等。这些方法有不同的名称,因为这里重载不是一个好主意

原因是,当您执行
sum(t->{…})
时,编译器无法推断要调用哪个方法;实际上,在推断隐式lambda表达式的类型(基于该方法的签名)之前,它需要首先解决方法重载问题,选择一个方法

这令人失望。在早期阶段,Java8有一个更复杂的推理机,
Comparator
重载了
comparing()
方法;和
sum(t->{…})
也可以正确推断。不幸的是,他们决定简单地解决这个问题

重载带有函数参数的方法的经验法则:函数接口的算术必须不同,除非两者都是0

// OK, different arity
m1( X->Y )
m1( (X1, X2)->Y )

// not OK, both are arity 1
m2( X->Y )
m2( A->B )

    m2( t->{...} ); // fail; type of `t` cannot be inferred 

// OK! both are arity 0
m3( ()->Y )
m3( ()->B )
使用arity 0重载可以的原因是lambda表达式不是隐式的-所有参数类型都是已知的(因为没有参数!),我们不需要上下文信息来推断lambda类型

m3( ()-> return new Y() );   // lambda type is ()->Y
m3( ()-> return new B() );   // lambda type is ()->B

与Java 7、6和5相同:你不能。这是消息告诉你的。你建议使用包装器接口是好的,但不是“干净的”,因为每次需要引入新操作或新类型时,
Test
都需要修改。只需两种类型(整数或双倍)和两种操作(求和和和和和乘法),您需要4个方法。更不用说为每种类型创建的包装器接口了。这是API的一个大爆炸。不过,对于链接来说,这并不很好:)请参阅类似的示例
comparingDouble(ToDoubleFunction)
comparingit(ToIntFunction)
-这些方法有不同的名称,因为重载不是一个好主意。只使用不同的方法名称要容易得多:)
sumInt,sumDouble
,通过在
Test
中设置
操作
a
受保护的
方法就可以很容易地安排这些方法,在子类中创建一个
sumXYZ
方法,并在其中调用重写的
操作
方法:但正如我所说,有很多方面的改进超出了答案的范围。。