The Double Colon Operator in Java 8 – Java 8中的双冒号操作符

最后修改: 2016年 1月 26日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick article, we’ll discuss the double colon operator ( :: ) in Java 8 and go over the scenarios where the operator can be used.

在这篇文章中,我们将讨论Java 8中的双冒号操作符 ( ::),并介绍可以使用该操作符的情况。

2. From Lambdas to Double Colon Operator

2.从Lambdas到双冒号操作符

With Lambdas expressions, we’ve seen that code can become very concise.

通过Lambdas表达式,我们已经看到代码可以变得非常简洁。

For example, to create a comparator, the following syntax is enough:

例如,为了创建一个比较器,以下语法就足够了。

Comparator c = (Computer c1, Computer c2) -> c1.getAge().compareTo(c2.getAge());

Then, with type inference:

然后,通过类型推理。

Comparator c = (c1, c2) -> c1.getAge().compareTo(c2.getAge());

But can we make the code above even more expressive and readable? Let’s have a look:

但我们能不能使上面的代码更有表现力和可读性呢?让我们来看看。

Comparator c = Comparator.comparing(Computer::getAge);

We’ve used the :: operator as shorthand for lambdas calling a specific method – by name. And the end, result is of course even more readable syntax.

我们使用::操作符作为λ调用特定方法的简写–通过名称。而最终的结果当然是更可读的语法。

3. How Does It Work?

3.它是如何工作的?

Very simply put, when we are using a method reference – the target reference is placed before the delimiter :: and the name of the method is provided after it.

很简单,当我们使用方法引用时–目标引用被放在分界符::之前,而方法的名称则在它之后。

For example:

比如说。

Computer::getAge;

We’re looking at a method reference to the method getAge defined in the Computer class.

我们正在查看定义在Computer类中的getAge方法的方法引用。

We can then operate with that function:

然后我们可以用这个功能进行操作。

Function<Computer, Integer> getAge = Computer::getAge;
Integer computerAge = getAge.apply(c1);

Notice that we’re referencing the function – and then applying it to the right kind of argument.

注意,我们正在引用函数–然后将其应用于正确的参数类型。

4. Method References

4.方法参考

We can make good use of this operator in quite some scenarios.

我们可以在相当多的情况下很好地利用这个运算符。

4.1. A Static Method

4.1.一个静态的方法

First, we’re going to make use of a static utility method:

首先,我们要利用一个静态实用方法

List inventory = Arrays.asList(
  new Computer( 2015, "white", 35), new Computer(2009, "black", 65));
inventory.forEach(ComputerUtils::repair);

4.2. An Instance Method of an Existing Object

4.2.一个现有对象的实例方法

Next, let’s have a look at an interesting scenario – referencing a method of an existing object instance.

接下来,让我们看看一个有趣的场景–引用一个现有对象实例的方法

We’re going to use the variable System.out – an object of type PrintStream which supports the print method:

我们将使用变量System.out–一个支持print方法的PrintStream类型的对象。

Computer c1 = new Computer(2015, "white");
Computer c2 = new Computer(2009, "black");
Computer c3 = new Computer(2014, "black");
Arrays.asList(c1, c2, c3).forEach(System.out::print);

4.3. An Instance Method of an Arbitrary Object of a Particular Type

4.3.某一特定类型的任意对象的实例方法

Computer c1 = new Computer(2015, "white", 100);
Computer c2 = new MacbookPro(2009, "black", 100);
List inventory = Arrays.asList(c1, c2);
inventory.forEach(Computer::turnOnPc);

As you can see, we’re referencing the turnOnPc method not on a specific instance, but on the type itself.

正如你所看到的,我们引用的turnOnPc方法不是在一个特定的实例上,而是在类型本身上。

At line 4 the instance method turnOnPc will be called for every object of inventory.

在第4行,实例方法turnOnPc将为inventory的每个对象调用。

And this naturally means that – for c1 the method turnOnPc will be called on the Computer instance and for c2 on MacbookPro instance.

这自然意味着–对于c1,方法turnOnPc将在Computer实例上被调用,对于c2,在MacbookPro实例上被调用。

4.4. A Super Method of a Particular Object

4.4.某一特定对象的超级方法

Suppose you have the following method in the Computer superclass:

假设你在Computer超类中有以下方法。

public Double calculateValue(Double initialValue) {
    return initialValue/1.50;
}

and this one in MacbookPro subclass:

而这个是在MacbookPro子类中。

@Override
public Double calculateValue(Double initialValue){
    Function<Double, Double> function = super::calculateValue;
    Double pcValue = function.apply(initialValue);
    return pcValue + (initialValue/10) ;
}

A call to calculateValue method on a MacbookPro instance:

在一个MacbookPro实例上调用calculateValue方法。

macbookPro.calculateValue(999.99);

will also produce also a call to calculateValue on the Computer superclass.

也会产生对Computer超类的calculateValue的调用。

5. Constructor References

5.构造函数引用

5.1. Create a New Instance

5.1.创建一个新的实例

Referencing a constructor to instantiate an object can be quite simple:

引用一个构造函数来实例化一个对象可以很简单。

@FunctionalInterface
public interface InterfaceComputer {
    Computer create();
}

InterfaceComputer c = Computer::new;
Computer computer = c.create();

What if you have two parameters in a constructor?

如果你在构造函数中有两个参数怎么办?

BiFunction<Integer, String, Computer> c4Function = Computer::new; 
Computer c4 = c4Function.apply(2013, "white");

If parameters are three or more you have to define a new Functional interface:

如果参数是三个或更多,你必须定义一个新的功能接口。

@FunctionalInterface 
interface TriFunction<A, B, C, R> { 
    R apply(A a, B b, C c); 
    default <V> TriFunction<A, B, C, V> andThen( Function<? super R, ? extends V> after) { 
        Objects.requireNonNull(after); 
        return (A a, B b, C c) -> after.apply(apply(a, b, c)); 
    } 
}

Then, initialize your object:

然后,初始化你的对象。

TriFunction <Integer, String, Integer, Computer> c6Function = Computer::new;
Computer c3 = c6Function.apply(2008, "black", 90);

5.2. Create an Array

5.2.创建一个数组

Finally, let’s see how to create an array of Computer objects with five elements:

最后,让我们看看如何创建一个有五个元素的Computer对象的数组。

Function <Integer, Computer[]> computerCreator = Computer[]::new;
Computer[] computerArray = computerCreator.apply(5);

6. Conclusion

6.结论

As we’re starting to see, the double colon operator – introduced in Java 8 – will be very useful in some scenarios, and especially in conjunction with Streams.

正如我们开始看到的,双冒号操作符–在Java 8中引入–在某些情况下会非常有用,特别是在与Streams结合时。

It’s also quite important to have a look at functional interfaces for a better understanding of what happens behind the scenes.

为了更好地了解幕后发生的事情,看一看功能界面也是相当重要的。

The complete source code for the example is available in this GitHub project – this is a Maven and Eclipse project so that it can be imported and used as-is.

该示例的完整源代码可在这个GitHub项目中获得 – 这是一个Maven和Eclipse项目,因此可以按原样导入和使用。