Lambda

  • 是一种语法糖: 对之前的一些编码做了一定的简化(优化)

  • 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表示

  • 使用来代替匿名内部类

  • 代替的匿名类是有条件的

    1. 匿名内部类必须实现函数式接口

      • 必须实现接口 。继承父类不行。

      • 所谓函数式接口,接口中只能有一个抽象方法

    2. 必须有可以推导上下文

      • 直白一点,就是不能是匿名对象

  • 将匿名内部类 替换成 lambda

interface CompareStrategy{
    boolean compare(Goods g) ;
}

public static List 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 find(CompareStrategy compare){
    //存储符合条件的商品
    List 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.右边:你对这个接口中的抽象方法的具体的重写逻辑

你可能感兴趣的:(java,开发语言)