1. Lambda表达式简介
Lambda表达式是java8的重要更新,也是一个被广大程序员期待已久的新特性,Lambda表达式允许使用更加简洁的代码来创建只有一个抽象方法的接口(这种接口被称为函数式接口)的实例.
Lambda表达式的主要作用是代替匿名内部类的烦琐的语法,他主要由三部分组成:
-
形参列表 :形参列表允许省略形参类型.如果形参列表里只有一个参数,甚至形参列表的圆括号都可 以省略.
-
(箭头(->) :必须通过英文输入法中横线和大于号组成.
-
代码块 :如果代码块只包含一条语句,Lambda表达式允许省略代码块的花括号, 如果代码块已有一行return语句,甚至可以省略return关键字.
2.Lambda表达式使用示例
interface Eatable{
void teste();
}
interface Flyable{
void fly(String name);
}
interface Addable{
int add(int a,int b);
}
public class LamdbaQs{
//调用Eatable接口对象
public void eat(Eatable e){
System.out.println(e);
e.teste();
}
//调用Flyable
public void drive(Flyable f){
System.out.println(f);
f.fly("哈哈!");
}
//调用Addable
public void test(Addable a){
System.out.println(a);
System.out.println("长方形的面积为:"+a.add(5,3));
}
public static void main(String[] args){
LamdbaQs lq=new LamdbaQs();
//实例1: Lamdba表达式的代码块只有一行代码的时候可以省略花括号;
//不用Lambda表达式的写法;
lq.eat(new Eatable(){
public void teste(){
System.out.println("苹果味道不错!");
}
});
//使用Lambda表达式的写法;
lq.eat(()-> System.out.println("苹果味道不错!"));
//实例2: Lambda表达式的形参列表只有一个参数的时候可以省略 参数列表的圆括号;
//不用Lambda表达式的写法;;
lq.drive(new Flyable(){
public void fly(String name){
System.out.println("今天天气真不错,我和"+name+"出去玩!");
}
});
//使用Lambda的写法;
lq.drive(name -> {
System.out.println("今天天气真不错!"+name+"出去玩!");
});
//实例3: Lambda表达式的代码块只有一条语句的时候,可以省略花括号,即使该表达式需要返回值,也可以省略return;关键字!
//不用Lambda表达式的写法;
lq.test(new Addable(){
public int add(int a ,int b){
return a*b;
}
});
//使用Lambda表达式的写法
lq.test((a,b)-> a*b);
}
}
上面程序中可以看到有这么几行代码:
System.out.println(e);
System.out.println(f);
System.out.println(a);
他们的打印结果为:
cow.LamdbaQs$$Lambda$1/1510467688@5acf9800
cow.LamdbaQs$$Lambda$2/2055281021@5ca881b5
cow.LamdbaQs$$Lambda$3/798154996@28a418fc
可以看出他们传入的并不是 Eatable, Flyable, Addable 这三个接口 ,而是三个Lamdba表达式
而且上边的程序可以正常编译,运行 这说明Lambda表达式实际上会被当成一个"任意类型"至于到底需要当成何种类型的对象,就要取决于运行环境的需要了.
3.Lambda表达式与函数式接口
Lambda表达式也被成为"目标类型",Lambda表达式的目标类型必须是"函数式接口"(只有一个抽象方法的接口被成为函数式接口,函数式接口可以包含很多的默认方法,类方法,但只能声明一个抽象方法,换句话说只要有一个以上的抽象方法它就不是函数式接口).如果使用匿名内部类的方式来创建函数式接口的实例只需要实现一个抽象方法,这种情况完全可以用Lambda表达式来创建对象,该表达式创建出来的对象的目标类就是这函数式接口.
.
..
既然Lambda表达式是任意类型,目标类型,而且它的结果也会被当成对象来处理,那我们程序中完全可以使用Lambda表达式进行赋值.
//Runnable java本身提供的函数式接口
//Runnable接口中只包含一个抽象方法, Lambda表达式实现了这个接口里的唯一的,无参数的方法 因此下面的Lambda表达式则创建了一个Runnable对象
Runnable r = () -> {
for(int i= 1 ; i < 200 ; i++){
/////////////////////
}
}
//函数式接口
@FunctionalInterface
interface FInterface{
void run();
}
public void test(){
//使用函数式接口将Lambda表达式进行强制装换,这样就可以确定该表达式的目标类型为FInterface函数式接口.
Object obj=(FInterface) ()-> {
for(int i=0 ; i<100 ; i++){
///////////////
}
};
}
3.1.Lambda两个限制
-
Lambda表达式的目标类型必须是明确的函数式接口
-
Lambda表达式只能为函数式接口创建对象,Lambda表达式只能实现一个方法,因此它只能为只有一个抽象方法的接口(函数式接口)创建对象.
根据限制我们再来看一个示例:
Object obj=() -> {
for(int i=0; i<100 ; i++){
////////////////////////
}
}
上面这段程序运行后报错:不兼容类型,Object不是函数式接口.
那么我们来改一下呢:
Object obj=(Runnable) ()-> {
for(int i=0 ; i<100 ; i++){
///////////////
}
};
这样就好了, 我们把Lambda表达式强制装换为Runnable类型,这样就可以确定该表达式的目标类型为Runnable函数式接口.
提示: Java8专门为函数式接口提供了@FunctionalInterface注解,该注解通常放在接口定义前面,它对程序没有任何作用,只告诉编辑器必须严格检查这个必须是函数式接口,否则编译器就会报错.
4.方法引用与构造器引用
前面已经介绍过如果Lambda表达式的代码块只有一条代码,程序就可以省略Lambda表达式中代码块的花括号.不进如此如果Lambda表达式的代码块只有一条大妈,还可以在代码块中使用方法引用和构造器引用.
方法引用和构造器引用可以让Lambda表达式的代码更加简洁.他们都需要使用两个英文冒号.Lambda表达式支持下表这些引用方法:
种类 | 实例 | 对应的Lambda表达式 |
---|---|---|
引用类方法 | 类名 :: 类方法 | (a,b)->类名.类方法(a,b,...) |
引用特定对象的实例方法 | 特定对象::实例方法 | (a,b)->特定对象.实例方法(a,b,...) |
引用构造器 | 类名::new | (a,b,...)->new 类名(a,b,...) |
实例:
YourTest.java
import java.awt.*;
import javax.swing.*;
@FunctionalInterface
public interface YourTest{
JFrame win(String title);
}
Converter.java
@FunctionalInterface
public interface Converter{
Integer convert (String from);
}
MyTest.java
import java.awt.*;
import javax.swing.*;
public class MyTest {
public void test(Converter con){
System.out.println(con.convert("111111"));
}
public static void main(String[] args){
//引用类方法
//普通写法
Converter con2=new Converter(){
public Integer convert(String name){
return Integer.valueOf(name);
}
};
System.out.println(con2.convert("111111"));
//使用匿名内部类的常规写法;
MyTest test=new MyTest();
test.test(new Converter(){
public Integer convert(String name){
return Integer.valueOf(name);
}
});
//使用Lambda表达式写法;
Converter con =from -> Integer.valueOf(from);
Integer i=con.convert("9999");
System.out.println(i);
//方法引用代替Lamdba表达式,引用类方法;
Converter con3=Integer :: valueOf;
System.out.println(con3.convert("33333"));
//引用特定对象的实例方法
//普通写法
Converter con4=new Converter(){
public Integer convert(String name){
return "Java,HaHaHa!".indexOf(name);
}
};
System.out.println(con4.convert("a"));
//Lambda表达式写法
Converter con5=name -> "Java,HaHaHa!".indexOf(name);
System.out.println(con5.convert("a"));
//方法引用代替Lamdba表达式,引用特定对象的实例方法
Converter con6 ="Java,HaHaHa!" :: indexOf;
System.out.println(con6.convert("J"));
//引用构造器
//Lambda表达式写法
YourTest yt=(String a) -> new JFrame(a);
JFrame jf=yt.win("我的窗口!");
System.out.println(jf);
//构造器引用代替Lambda表达式写法
YourTest yt2 =JFrame :: new;
JFrame jf2=yt2.win("我的窗口!(构造器引用)");
System.out.println(jf2);
}
}
JFrame 是java Swing中的基本容器,与本主题无关只是一个示例.
提示:新手的话不建议直接使用Lambda表达式.
第一次发表文章,希望大家多多支持,多多点赞,多多评论,以后写出更好的文章和大家分享,写的不好的地方,还望大神多多指点,大家共同进步. 祝大家技术越来越好,薪资越来越高.
网友评论