如何使用功能接口

时间:2015-08-15 14:47:49

标签: java lambda java-8

我最近开始阅读有关java 8功能的内容,我对这似乎是一件非常基本的事情感到困惑。如何在功能样式中组织代码' ? 无论我做什么,它看起来都非常面向我。

最好用一个例子来解释我的问题。

    @FunctionalInterface
    public interface SubstringOperator {

        String splitAtLastOccurence(String plainText, String delimiter);

    }

让我们说在某些class我总是需要SubstringOperator接口的一个特定实现。我可以在构造函数中提供如下所示的实现:

public class SomeClass {

    private SubstringOperator substringOperator;

    public SomeClass() {

        substringOperator = (s, d) -> { return s.substring(s.lastIndexOf(d)+1);};
    }
}

我现在可以在SomeClass中的任何方法中使用此实现,如下所示:

 //...
String valueAfterSplit = substringOperator.splitAtLastOccurence(plainText, "=");

如果我现在希望添加另一个重用该特定SubstringOperator实现的类,我应该创建另一个通过getter公开实现的类吗?

我错过了一些明显的东西,或者:

  • 函数必须包含在类中才能重用它们?
  • 与面向对象的范例有何不同?

抛开Stream API和其他东西,我希望对java 8中用于功能样式编程的代码组织有基本的了解。

1 个答案:

答案 0 :(得分:4)

通常最好重用现有的功能接口而不是创建新接口。在您的情况下,BinaryOperator<String>就是您所需要的。最好根据变量的含义命名变量,而不是按类型命名变量。因此,你可能有:

public class SomeClass {
    private BinaryOperator<String> splitAtLastOccurence = 
        (s, d) -> s.substring(s.lastIndexOf(d)+1);
}

请注意,您可以简化单语句lambda,删除return关键字和大括号。它可以像这样应用:

String valueAfterSplit = splitAtLastOccurence.apply(plainText, "=");

通常,如果您的类始终使用相同的函数,则无需将其存储在变量中。改为使用普通旧方法:

protected static String splitAtLastOccurence(String s, String d) {
    return s.substring(s.lastIndexOf(d)+1);
}

请致电:

String valueAfterSplit = splitAtLastOccurence(plainText, "=");

当按功能参数化另一个类或方法时,函数很好,因此它可以用于不同的函数。例如,您正在编写一些通用代码,可以处理带有附加other字符串的字符串列表:

void processList(List<String> list, String other, BinaryOperator<String> op) {
    for(int i=0; i<list.size(); i++) {
        list.set(i, op.apply(list.get(i), other));
    }
}

或者更多java-8风格:

void processList(List<String> list, String other, BinaryOperator<String> op) {
    list.replaceAll(s -> op.apply(s, other));
}

通过这种方式,您可以将此方法用于不同的功能。如果您已经如上所述定义了splitAtLastOccurence静态方法,则可以使用方法引用重用它:

processList(myList, "=", MyClass::splitAtLastOccurence);