-
是一种语法糖: 对之前的一些编码做了一定的简化(优化)
-
lambda是对一定条件下匿名内部类编码的一种简化。
一 内部类和匿名内部类
1 内部类
写在内部的类,写在哪个内部?
类的内部:成员内部类
-
相当于类的一个成员 :原来有属性, 方法。现在多了一个内部类
-
成员内部类被当成了一个类成员。类成员有4种访问权限
-
所以成员内部类也可有4种访问权限
-
因为类的成员还可以用static关键字修饰
-
所以成员内部类也可以使用static关键字修饰
class B{
class A{}
}
方法内部:局部内部类
-
类似于方法中的一个局部变量
-
只能在当前的方法中使用
class B{
public void t1(){
class A{}
A a = new A();
}
public void t2(){
A a = new A(); //错误
}
}
-
内部类总结:
-
目前为止我们的类有3种 : 普通类,成员内部类,局部内部类
-
普通类: 可以在任意地方使用
-
成员内部类:就像类的成员一样(属性和方法)。可以被当前中的所有方法使用。
-
如果有这么一种情况:有一个类只需要在某一个特定的类中使用,不需要在其他类中使用就可以定义为成员内部类
-
-
局部内部类:就像方法中的局部变量,只能在当前方法中使用。
-
如果有这么一个场景。有一个类只需要在当前方法中定义并使用,其他方法中都不需要使用,就可以定义为局部内部类。
-
-
-
2 匿名内部类
-
本身也是内部类(成员,局部)
-
所谓的匿名,就是没有名字,不提前定义这个类。
-
如果不提前定义这个类,如何去使用这个类呢?
-
当定义类的使用直接使用。
类似:(匿名对象)
A a = new A(); a 就是对象的名字
new A().t1();
-
匿名内部类必须基于明确的父类或接口,记住匿名内部类不一定只有实现接口一种形式
-
创建语法如下:
{
int i ;
public void t1();
}
new 父类/接口(){
int i ;
public void t1();
};
public class Test1 {
public static void main(String[] args) {
A a = new A(){
public void t1(){}
};
//如果有一个类他需要继承B类,但是他只在这一段代码中使用,写成下面的形式表示有一个类继承了B
//这个类没有名字,也就是匿名内部类
B b = new B(){
};
//这个和上面的一样,就是创建了一个继承Object类的子类,只不过这个子类只在这里使用一次,所以写成匿名内部类的形式。
Object c = new Object(){
};
}
}
interface A{
void t1();
}
class B{}
class C1 implements A{
@Override
public void t1() {
}
}
class C2 extends B{}
二 策略模式
-
在策略模式设计中,经常会使用的匿名内部类
-
自然在jdk8之后,也会经常用到lambda
-
场景: 有一系列类似的操作,但具体的执行不同
-
假设有100种商品 (编号, 名称,价格,销售量,库存量,评分)
-
现在的需求时准备从这100种商品中获取符合需求的商品
-
//Object1(fn) , Object2(fn) , Object3(fn) , Object4() , Object5()
//ObjectStrategy(fn)
public List<商品> find(ObjectStrategy(fn)){
//遍历商品,判断上商品是否符合需求 (价格<30 , 销售量>10000,库存量>1000 , 评分==5)
//boolean object.fn(商品);
//不符合pass
//符合 add
return list ;
}
三 Lambda表示
-
使用来代替匿名内部类
-
代替的匿名类是有条件的
-
匿名内部类必须实现函数式接口
-
必须实现接口 。继承父类不行。
-
所谓函数式接口,接口中只能有一个抽象方法
-
-
必须有可以推导上下文
-
直白一点,就是不能是匿名对象
-
-
-
将匿名内部类 替换成 lambda
interface CompareStrategy{
boolean compare(Goods g) ;
}
public static List<Goods> findByPriceLt5(){
//return find(new CompareStrategy(){
// boolean compare(Goods x){return g.price<5;}
// });
/*
只要你了解匿名内部类对象的创建
地球人都知道,应该new CompareStrategy(){
boolean compare(Goods x){return g.price<5;}
}
当然也有地球人不知道的代码部分 ,参数名不知道 , 方法体不知道
所谓的lambda语法糖, 就是将匿名内部类对象中地球人都知道的部分去掉, 保留不知道的部分
(x){return g.price<5;}
将两个部分使用->隔开
(x)->{return g.price<5;}
*/
//return find(CompareStrategy匿名内部类对象);
return find((g)->{return g.price < 5 ;})
}
private static List<Goods> find(CompareStrategy compare){
//存储符合条件的商品
List<Goods> list = new ArrayList<>();
for(Goods g : goodsList){
//判断当前的g是否符合条件
//符合条件list.add(g);
boolean f = compare.compare(g);
if(f){
list.add(g);
}
}
return list ;
}
四 Lambda细节
1 参数
-
可以保留参数类型,也可以省略参数类型
(Goods g)->{}
(g) -> {}
-
如果只有1个参数,可以省略()
(g)->{}
g->{}
-
如果有多个参数,不可以省略()
(g1,g2)->{}
2 方法体
-
如果只有一行代码,可以省略{}
(g)->{System.out.print(g);}
g->System.out.print(g);
-
如果只有一行代码,带有return返回值。可以省略{}和return
(g)->{return g.name ;}
g->g.name ;
五 方法引用
-
所谓的方法引用 是在lambda方法中 只调用了另个方法,没有其他代码
-
调用的另一个方法和当前lambda有相同的api声明
-
此时就可以使用方法引用了
-
具体的语法有以下3种:
1 对象方法引用
interface A{
void t1(int i) ;
}
class B{
public void t2(int j){
System.out.println(j);
}
}
B b = new B();
A a1 = new A(){
public void t1(int i){
b.t2(i);
}
}
A a2 = (int i)->{ b.t2(i);} ;
A a3 = i->b.t2(i) ;
A a4 = b::t2 ;
-
this 和 super对象引用
2 类方法引用
interface A{
void t1(int i) ;
}
class B{
public static void t2(int j){
System.out.println(j);
}
}
// A a = new A()
A a1 = new A(){
public void t1(int i){
B.t2(i);
}
}
A a2 = (int i)->{ B.t2(i);} ;
A a3 = i->B.t2(i) ;
A a4 = B::t2 ;
//目前为止,都是在new对象,还没有调用对象方法呢
a4.t1(10);
3 构造方法引用
-
经常在工厂模式中出现
interface A{
Object t1(int i,String s) ;
}
class B{
public B(int j , String str){
//....
}
}
A a1 = new A(){
Object t1(int i,String s){
return new B(i, s) ;
}
};
A a2 = (i,s)->{return new B(i,s);};
A a3 = (i,s)->new B(i,s);
A a4 = B::new ;
//....
B b = (B)a4.t1();
Lambda表达式的语法特点:
1.Lambda表达式 引入了一个箭头符号 ->
2.箭头符号 -> 把Lambda表达式分成左右两部分
3.左边:写这个接口中的抽象方法的形参列表。
4.右边:你对这个接口中的抽象方法的具体的重写逻辑