Lambda表达式简介
在java里面用的很多的是匿名内部类,具体如下:
interface Message{
public void print(String str);
}
public class TestDemo {
public static void main(String[] args) {
Message msg=new Message(){
@Override
public void print(String str) {
System.out.println(str);
}
};
msg.print("Hello World");
}
}
实际上真正需要的就是一个输出语句,但是由于java类结构的限制,很多人都觉得代码过于麻烦。于是很多人开始怀念起以前的函数式编程:
interface Message{
public void print(String str);
}
public class TestDemo {
public static void main(String[] args) {
Message msg=(s) -> System.out.println(s);
msg.print("Hello World!");
}
}
通过上面的例子发现,语句变得简单了。
整个表达式的语句如下:
(s) -> System.out.println(s);
(参数,名称可以随意起,)
组成要求如下:
(参数):与Message接口定义的print()方法的参数类型一致,但是此处不需要进行声明。如果追求完美度,也可以声明类型:
Message msg=(String s) -> System.out.println(s);
- ->:固定语法,表示将参数指向方法体;
- 方法体:就是进行匿名内部类实现方法的时候所编写的内容。
总结
Lambda表达式最重要的是解决匿名内部类的问题
如果想要使用Lambda表达式,那么必须以接口为主,而且接口里面只能够定义一个抽象方法。
使用Lambda表达式
java8的Lambda表达式的语法有三种定义:
- (params)->单行语句;
- (params)->表达式;
- (params)->{多行语句};
单行语句的示例如下:
interface Message{
public void print();
}
public class TestDemo {
public static void main(String[] args) {
Message msg=() -> System.out.println("Hello World!");
msg.print();
}
}
有表达式的Lambda语句示例如下,
interface MyMath{
public int add(int x, int y); //现在有参数
}
public class TestDemo {
public static void main(String[] args) {
MyMath mm=(x,y)->x+y; //代码省略了
System.out.println("加法计算结果:"+mm.add(1, 2));
}
}
多行语句的示例如下
interface MyMath{
public int add(int x, int y); //现在有参数
}
public class TestDemo {
public static void main(String[] args) {
MyMath mm=(x,y)->{
int sum=x+y;
return sum;
};
System.out.println("加法计算结果:"+mm.add(1, 2));
}
}
由于接口里面的方法只能有一个,所以我们可以在接口上面加Annotation来声明这个接口是函数式的接口。
@FunctionalInterface
interface MyMath{
public int add(int x, int y); //现在有参数
}
在jdk1.8之前,所有的接口定义的方法的权限都属于public,可是这个规定被半打破了,接口允许我们动态扩充了。
一个我们已经实现好的接口,突然又想增加新的方法,但是这个增加的方法又不想影响子类。这个情况下可以使用default方法。
@FunctionalInterface
interface Message{
String getInfo();
default void print(){
//default方法不要求子类强制实现
System.out.println("Hello Java8");
}
}
public class TestDemo {
public static void main(String[] args) {
Message msg=()->"Hello World!";
System.out.println(msg.getInfo());
msg.print();
}
}
这个新功能已经颠覆了传统的java开发思路。
除此之外,在接口里面也可以用static定义方法。
@FunctionalInterface
interface Message{
String getInfo();
default void print(){
//default方法不要求子类强制实现
System.out.println("Hello Java8");
}
static void fun(){
System.out.println("Hello static interface method");
}
}
public class TestDemo {
public static void main(String[] args) {
Message msg=()->"Hello World!";
System.out.println(msg.getInfo());
msg.print();//直接调用接口里面视线好的方法
Message.fun();//通过Message接口直接调用fun方法
}
}
这种新功能对于以前java接口的颠覆是属于兼容是的扩充。它在整个过程中没有对子类进行任何强制性要求。
方法引用
方法引用是java8新增加的一个功能,可以理解为复制版的Lambda。
所谓的方法引用就是讲一个特定类的方法功能映射过来,然后通过接口中的方法,利用lambda表达式实现方法体的定义,这种定义的形式分为如下四种。
- 类中静态方法的引用(类名称::静态方法名称;)
- 类中普通方法的引用(实例化的对象名称::普通方法;)
- 类中构造方法的yiny(类名称::new();)
- 特定义的任意方法的引用(类名称::方法名称)
引用构造方法示例:
@FunctionalInterface
interface Message{
public void getInfo();//本方法没有参数也没有返回值
}
class Book{ //这是一个独立的类,和message接口没有任何关系
public Book(){//这个时候的构造方法是无参的,没有返回值
System.out.println("Hello java8");
}
}
public class TestDemo {
public static void main(String[] args) {
Message msg=Book :: new;//引用构造方法
System.out.println(msg.getClass());//输出class com.zcc.test.TestDemo$$Lambda$1/321001045
msg.getInfo(); //这个时候调用的是构造方法的构造体
}
}
我们发现使用Lambda表达式定义的任何抽象操作,都可以引用与之结构完全无关的操作,因为要的只是方法体,调用接口的抽象方法时实际上之行的是引用的方法体内容。
范例:引用静态方法
在String里面定义了许多方法:public static String valueOf(int i),引用此方法。
此时定义的接口就需要设置输入值以及返回值,为了让接口更适合各种方法,使用泛型。
/**
* 函数式接口
*@param <P> 方法的参数类型
*@param <R> 方法的返回值类型
*/
@FunctionalInterface
interface Message<P,R>{
public R getInfo(P p);//方法有参数,有返回值
}
public class TestDemo {
public static void main(String[] args) {
Message<Integer,String> msg= String::valueOf;
System.out.println(msg.getInfo(1000));//返回此时返回的是字符串1000
System.out.println(msg.getInfo(1000).length());//长度是5
}
}
在进行方法引用的时候还可以针对特定类型的方法实现引用。
范例:特定类型的方法引用
在String类里面有一个不区分大小写判断内容的方法:public int compareToIgnoreCase(String str)
本次将在Comparator接口上引用这个方法。
public class TestDemo {
public static void main(String[] args) {
String [] data=new String[]{"zcc","zbq","bbg","java","lambda","csdn"};
Comparator<String> cmp= String :: compareToIgnoreCase;//特定的类型方法
Arrays.sort(data,cmp);
System.out.println(Arrays.toString(data));//[bbg, csdn, java, lambda, zbq, zcc]
}
}
范例:构造方法的引用,本次引用的是有参构造方法
class Book{
private String title;
private double price;
public Book(String title, double price) {//存在有参构造方法
this.title = title;
this.price = price;
}
@Override
public String toString() {
return "Book [title=" + title + ", price=" + price + "]";
}
}
@FunctionalInterface
interface Creator<R extends Book>{
public R create(String title,double price);
}
public class TestDemo {
public static void main(String[] args) {
Creator<Book> cre = Book :: new;
System.out.println(cre.create("伤不起的程序员", 79.8 ));//Book [title=伤不起的程序员, price=79.8]
}
}
等于将构造方法设置了引用,然后利用引用的方法创建了类的对象。
建议掌握静态方法,普通方法,构造方法这三种引用操作。