深入理解Java双冒号(::)运算符的使用

Posted Firm陈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解Java双冒号(::)运算符的使用相关的知识,希望对你有一定的参考价值。

Jdk8中有好多新的特性,比如引入Lambda,简化代码的书写等等
我们先看一个关于Lambda的使用

/**
* 输出list
 */
@Test
public void test() 
	String[] array = "aaaa", "bbbb", "cccc";
	List<String> list = Arrays.asList(array);
	
	//Java 7 
	for(String s:list)
		System.out.println(s);
	
	
	//Java 8
	list.forEach(System.out::println);

其中list.forEach(System.out::println);就是Java 8中的Lambda写法之一, 有没有特别注意到输出语句跟我们平时写的syso语句不一样,常规输出语句是这样的:

System.out.println("流浪地球拍的不错哦!");

这里面使用到了::, 有点意思,来认识一下这个新东西!

双冒号(::)
英文:double colon,双冒号(::)运算符在Java 8中被用作方法引用(method reference),方法引用是与lambda表达式相关的一个重要特性。它提供了一种不执行方法的方法。为此,方法引用需要由兼容的函数接口组成的目标类型上下文。

Method References
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it’s often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.
关于方法引用的描述,摘自oracle官网

大致意思是,使用lambda表达式会创建匿名方法, 但有时候需要使用一个lambda表达式只调用一个已经存在的方法(不做其它), 所以这才有了方法引用!
以下是Java 8中方法引用的一些语法:

  • 静态方法引用(static method)语法:classname::methodname 例如:Person::getAge
  • 对象的实例方法引用语法:instancename::methodname 例如:System.out::println
  • 对象的超类方法引用语法: super::methodname
  • 类构造器引用语法: classname::new 例如:ArrayList::new
  • 数组构造器引用语法: typename[]::new 例如: String[]:new

如果上的语法太枯燥,那就通过一些例子来加强对它的理解:

静态方法语法使用例子:

import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
 * 
 * @author zhoufy
 * @date 2019年2月20日 下午2:19:13
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan("com.zhoufy")
public class Demo 
	@Test
	public void test() 
		List<String> list = Arrays.asList("aaaa", "bbbb", "cccc");
		
		//静态方法语法	ClassName::methodName
		list.forEach(Demo::print);
	
	
	public static void print(String content)
		System.out.println(content);
	

类实例方法语法使用例子:

import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
 * 
 * @author zhoufy
 * @date 2019年2月20日 下午2:19:13
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan("com.zhoufy")
public class Demo 
	@Test
	public void test() 
		List<String> list = Arrays.asList("aaaa", "bbbb", "cccc");
		
		//对象实例语法	instanceRef::methodName
		list.forEach(new Demo()::print);
	
	
	public void print(String content)
		System.out.println(content);
	


超类方法语法使用例子:

import java.util.Arrays;
import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;


/**
 * @author zhoufy
 * @date 2019年2月20日 下午2:41:38
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan("com.zhoufy")
public class Example extends BaseExample

	@Test
	public void test() 
		List<String> list = Arrays.asList("aaaa", "bbbb", "cccc");
		
		//对象的超类方法语法: super::methodName 
		list.forEach(super::print);
	


class BaseExample 
	public void print(String content)
		System.out.println(content);
	


类构造器语法使用例子:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
 * 
 * @author zhoufy
 * @date 2019年2月20日 下午2:19:13
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ComponentScan("com.zhoufy")
public class Example 

	@Test
	public void test() 
		InterfaceExample com =  Example::new;
		Example bean = com.create();	
		System.out.println(bean);
	


interface InterfaceExample
	Example create();


如果是带参数的构造器,示例如下:

/**
 * @author zhoufy
 * @date 2019年2月20日 下午2:19:13
 */
public class Example 
	
	private String name;
	
	Example(String name)
		this.name = name;
	
	
	public static void main(String[] args) 
		InterfaceExample com =  Example::new;
		Example bean = com.create("hello world");
		System.out.println(bean.name);
	

interface InterfaceExample
	Example create(String name);


这里需要特别注意的是:Example 类并没有implements InterfaceExample接口哦!!!

数组构造器语法使用例子:

import java.util.function.Function;

/**
 * @author zhoufy
 * @date 2019年2月20日 下午2:19:13
 */
public class Example 
	public static void main(String[] args) 
		Function <Integer, Example[]> function = Example[]::new;
		Example[] array = function.apply(4);	//这里的4是数组的大小
		
		for(Example e:array)
			System.out.println(e);	//如果输出的话,你会发现会输出4个空对象(null)
		
	

这里是借用jdk自带的java.util.function.Function类实现的,如果想要自定义接口


/**
 * 
 * @author zhoufy
 * @date 2019年2月20日 下午2:19:13
 */
public class Example 
	
	public static void main(String[] args) 
		Interface <Integer, Example[]> function = Example[]::new;
		Example[] array = function.apply(4);	//这里的4是数组的大小
		
		for(Example e:array)
			System.out.println(e);
		
	


@FunctionalInterface
interface Interface<A, T>
	T apply(A a); 


以上是关于深入理解Java双冒号(::)运算符的使用的主要内容,如果未能解决你的问题,请参考以下文章

Java 8 中的 ::(双冒号)运算符

理解 Java 方法引用(方法引用符:“双冒号 :: ”)

java笔记java中的lambda表达式和双冒号(::)运算符

java8 :: 用法 (JDK8 双冒号用法)

Java 8 Lambda表达式之方法引用 ::双冒号操作符

Java 8 Lambda表达式之方法引用 ::双冒号操作符