学习Lambda表达式中的方法引用:若Lambda体中有方法已经实现了,我们可以使用“方法引用”。(可以理解“方法引用”是Lambda表达式的另外一种表现方式)
主要有三种语法格式:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
我们举个例子来看一下:
// 方法引用——1.对象::实例方法名
@Test
public void test() {
//之前我们使用的lambda表达式格式
Consumer<String> con=(x)->System.out.println(x);//消费者函数接口
con.accept("我们一起加油");
//其实上面这个也是使用了方法的引用,但是不是我们接下来要展示的一种表现方式,他们都是调用了打印流的println方法
//对象::实例方法名
PrintStream ps=System.out;
Consumer<String> con1=ps::println;
con.accept("小杨真帅");
Enployee e=new Enployee();
Supplier<String> sup=e::getName;
System.out.println(sup.get());//null
}
但是这里我们要强调一下:我们需要实现的这个接口中的抽象方法中的参数列表和返回值类型要和我们当前调用这个实现方法的参数列表和返回值类型一致
这是Println实现方法的源码:
/**
* Prints a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>String</code> to be printed.
*/
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
这是消费性接口customer的抽象方法源码:
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
让我们看看 类::静态方法名的方法引用方式:
//方法引用——2.类名::静态方法名
@Test
public void test2(){
//我们之前使用Lambda表达式比较两个整数的方法
Comparator<Integer> com=(x,y)->Integer.compare(x, y);
int i= com.compare(2, 3);
System.out.println(i);//-1 说明2比3小
//使用 类名::静态方法名 的方式来比较两个数的大小
//在Integer中,compare是一个静态方法
Comparator<Integer> com2=Integer::compare;
int i2=com2.compare(5, 4);
System.out.println(i2);//1 说明5比4大
}
对于类::静态方法名这种方法引用一样,需要实现的接口中的抽象方法的参数列表和返回值类型要和我们方法引用的实现方法的参数列表和返回值类型一致
再让我们看看 类::静态方法名的方法引用方式:
//方法引用——类::实例方法名
@Test
public void test3(){
//我们之前使用Lambda表达式比较两个字符串是否相等
BiPredicate<String,String> bp=(x,y)->x.equals(y);//断言性接口
Boolean b= bp.test("123", "123");
System.out.println(b);//true
//我们使用 类名::实例方法名 的方式来比较两个数的大小
//在Lambda表达式参数的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数的时候,我们就可以使用 类名::实例方法名的方式来调用
BiPredicate<String , String> bp2=String::equals;
Boolean b2= bp.test("123", "123");
System.out.println(b);//true
}
这里有一个注意的点:什么时候我们使用类::实例方法名的方法引用?当我们有两个参数,第一个参数是实例方法的调用者,第二个参数是实例方法中的参数,这时候我们就可以使用类::实例方法名的方法引用方式
①方法引用——构造器引用(类名::new)
1.我们先创建一个Enployee实体类
public class Enployee {
private Integer id;
private String name;
private Integer age;
private Integer salary;//薪水
public Enployee() {
}
public Enployee(Integer id) {
this.id=id;
}
public Enployee(Integer id, String name, Integer age, Integer salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((salary == null) ? 0 : salary.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Enployee other = (Enployee) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (salary == null) {
if (other.salary != null)
return false;
} else if (!salary.equals(other.salary))
return false;
return true;
}
@Override
public String toString() {
return "Enployee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
使用构造器引用(类名::new)
@Test
public void test4(){
//之前Lambda表达式
Supplier<Enployee> sup=()->new Enployee();
System.out.println(sup.get());
//构造器引用方式
Supplier<Enployee> sup2=Enployee::new;//供给性接口
System.out.println(sup.get());//之间调用new出来的对象
}
这里需要注意的地方:如果说调用有参构造,就需要在函数式接口的泛型处加上你对应的有参构造的参数类型,然后java8底层“类型推断”会自动匹配上。 函数式接口中的参数列表要和你想要通过的构造器的参数列表类型和个数一致!
调用Enployee的有参构造: public Enployee(Integer id) {this.id=id;}
@Test
public void test5(){
//之前Lambda表达式
Function<Integer, Enployee> fun2=(x)->new Enployee(x);
System.out.println(fun2.apply(400));
//使用构造器引用方式调用有参构造
Function<Integer, Enployee> fun=Enployee::new;
System.out.println(fun.apply(500));
}
②方法引用——数组引用(type::new)
@Test
public void test6(){
//之前Lambda表达式
Function<Integer, String[]> fun=(x)->new String[x];
String[] s=fun.apply(10);
System.out.println(s.length);//数组的长度是10
//使用数组引用方式
Function<Integer, String[]> fun2=String[]::new;
String[] s2= fun2.apply(20);
System.out.println(s2.length);//数组的长度是20
}