Lambda表达式

引入lambda

第一次使用

在test01 我们写了一个内部类 比较大小 实际有用的话就这一句 很麻烦

在test02 用lambda表达式优化

package com.lijiawei;

import org.junit.Test;

import java.net.Inet4Address;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeSet;

public class Testlambda {
    @Test
  public  void test01(){
      //原来使用treeset排序得写一个匿名内部类
      Comparator<Integer> com = new Comparator<Integer>(){
              @Override
              public int compare(Integer o1,Integer o2) {
              return Integer.compare(o1,o2);//实际就这一句话有用
          }
      };
      TreeSet<Integer> ts = new TreeSet<Integer>(com);
      ts.add(2);
      ts.add(1);
      System.out.println(ts);
  }
  @Test
    public void test02(){
        Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
        TreeSet<Integer> ts = new TreeSet<Integer>(com);
        ts.add(2);
        ts.add(1);
      System.out.println(ts);
  }
  @Test
    public void test03(){
    
    }
}

一个需求

查询所有年纪大于20的人

  List<Employee> list = Arrays.asList(
            new Employee("张三",28,5000),
            new Employee("李四",8,10000),
            new Employee("王五",38,2000),
            new Employee("赵六",48,4500)
    );
    @Test
    public void test03(){
        List<Employee> a = filterAge(list);
        System.out.println(a);
    }
//查出年龄大于10岁的
    public  List<Employee> filterAge(List<Employee> list){

        List<Employee> employees = new ArrayList<>();
        for (Employee e :list){
            if(e.getAge()>10){
                employees.add(e);
            }
        }
        return employees;
    }
//查出工资大于5000的
  public  List<Employee> filterAge2(List<Employee> list){

        List<Employee> employees = new ArrayList<>();
        for (Employee e :list){
            if(e.getSalary()>5000){ //和上面的方法就变了这一句话
                employees.add(e);
            }
        }
        return employees;
    }

如果我又加一个需求 要求出工资大于5000并且年龄大于20的人 那是不是又得写一个方法 需求一变 就要改变原来的代码 这样不好

策略模式优化

定义一个接口

package com.Inter;

public interface Myfilter<T> {
    public boolean test(T t);
}

定义实现类

package com.Inter;

import com.pojo.Employee;

public class ImplMyfilter implements Myfilter<Employee>{
    @Override
    public boolean test(Employee employee) {
        return employee.getAge()>35;
    }
}

测试类

public List<Employee> show(List<Employee> list , Myfilter<Employee> im ){
        List<Employee> employees =new ArrayList<>();
    for (Employee employee:list){
        if(im.test(employee)){
            employees.add(employee);
        }
    }
    return employees;
}

    @Test
    public void test04(){
        List<Employee> show = show(list, new ImplMyfilter());//如果需求变了 我把这个实例换一下就行
        System.out.println(show);
    }

如果需求在变 我们只需要增加一个实现类 在调用的时候 new 这个新写的实现类即可 使用场景:商场打折

我们发现策略模式有个缺点 : 创建新功能就得写一个类 所以在优化

匿名内部类优化

匿名内部类直接实现 就不用写类实现了

public void text(){
       List<Employee> l = show(list, new Myfilter<Employee>() {
            @Override
            public boolean test(Employee employee) {
                return employee.getSalary()>5000;
            }
        });
        System.out.println(l);
    }

匿名内部类优化可读性差 所以在优化

lambda表达式优化

 @Test
    public void text(){
       List<Employee> l = show(list,(e) -> e.getSalary()>5000);
        
        System.out.println(l);
    }

还能更简洁 之后使用stream优化 先来学习lambda

lambda语法

注意: j.k1.8以前 匿名内部类引用同级别的变量 那个变量必须显示的写final 8之后默认加了final

-> 操作符分为俩部分 左侧 是抽象类中要重写的方法的参数列表 右侧是要执行的功能

接口中只有一个方法

1无参无返回值

Runnble r = ( ) ->System.Out.Print(“你好”);

2有一个参数无返回值

Consumer c = ( x) ->System.out.Print(“你好”);

只有一个参数 小括号可以不写

3有多个参数有返回值 有多条执行语句

多条语句 使用大括号抱起来

Comparator com= (x,y)->{

​ System.out.Print(“你好”);

​ return Integer.compare(x,y);

}

4 如果只有一条语句

return 和大括号可以省略

Comparator com= (x,y) -> Integer.compare(x,y);

5不写数据类型

上面的xy 都没有写数据类型 因为jjvm编译器可以类型推断

比如 String[] str=[“aa”,“bb”,“cc”] 这里的内容就是推断出来的 如果你分开写就报错

String[] str; str=[“aa”,“bb”,“cc”] //报错

再看这个上面写过的 我们e按下点的时候就提示有getSalary方法 他怎么知道我是什么类型的呢?根据目标类型推断出这是什么类型

List l = show(list,(e) -> e.getSalary()>5000);

因为不能写方法名 当接口有多个方法时java不知道重写的是哪个方法 所以借口不能写多个抽象方法

函数式接口

只有一个抽象方法的接口叫函数式接口 在接口上加注解@FunctionInterface 可以帮我们检查这个接口是不是函数式接口

内置函数式接口

每次们用一个功能 都要自己定义一个函数式接口 java想到了这一点 所以有四个内置的接口

Consumer void acept(T t) 消费型接口

public class TestLamda{
        @Test
        public void test(){
            show(100,(a)-> System.out.println("消费了"+a));
    }
      public void show(Integer number, Consumer<Integer> consumer){
          consumer.accept(number);
      }
}

Supplier T get(); 供给型接口

package com.lijiawei;

import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class TestLamda{
        @Test
        public void test(){
        List l = show(10,() -> (int)(Math.random()*10));
            System.out.println(l);
    }
      public List<Integer> show(Integer number, Supplier<Integer> supplier){
            List<Integer> lists = new ArrayList<>();
          for (int i = 0; i <number ; i++) {
              lists.add(supplier.get());
          }
            return lists;
      }
}

Function<T,R> R apply(T t) 函数式接口

package com.lijiawei;

import org.junit.Test;

import java.util.function.Function;


public class TestLamda{
        @Test
        public void test(){
         String a = show("    helloworld    ",(x) ->x.trim() );
            System.out.println(a);
    }
      public String show(String str, Function<String,String> function){
            return function.apply(str);
      }
}

predicate boolean test(T t ) 断言型接口

方法引用与构造器引用

以下三种写法有个前提 我们写的lambda体的方法的返回值和参数列表要与 函数时接口的抽象方法保持一致

在lambda表达式中 我们写了参数列表 和 方法体并返回了一个东西 这写都是手动写出来的 引用不写但要保持一致

对象::实例方法名

package com.lijiawei;

import org.junit.Test;

import java.util.function.Consumer;

public class TestLamda{
    @Test
    public void show(){

        Consumer<String> consumer1 = System.out::println;
        consumer1.accept("zz");

    }
}

再看一个例子

无参有返回值 Math::random也必须无参无返回值

package com.lijiawei;

import org.junit.Test;

import java.util.function.Consumer;
import java.util.function.Supplier;

public class TestLamda{
    @Test
    public void show(){
        //Supplier<T> T get();
        Empoyee emp = new Employee();
        Supplier<Double> supplier =emp::getAge;
        Double d = supplier.get();
        System.out.println(d);

    }
}

类::静态方法名

package com.lijiawei;

import org.junit.Test;

import java.util.Comparator;
import java.util.function.Consumer;
import java.util.function.Supplier;

public class TestLamda{
    @Test
    public void show(){
        Comparator<Integer> com = Integer::compare;
        int a = com.compare(5,4);
        System.out.println(a);
    }
}

类::实例方法名

先用lambda表达式 需求 比较俩个字符串是否一样

   public void show(){
        BiPredicate<String,String> bp = (x,y)->x.equals(y);
       boolean b =bp.test("a","a");
        System.out.println(b);
    }

为什么类名能调用实例方法呢? 当第一个参数是实例方法的调用者 另一个参数是实例方法的参数时 才能这么调

方法引用格式

 public void show(){
        BiPredicate<String,String> bp = String::equals;
       boolean b =bp.test("a","a");
        System.out.println(b);
    }

构造器引用

如果 方法体是获取对象

Supplier<Employee> s = ()->new Employee();

可以这么写 那用的是有参构造还是无参构造呢 得看函数接口的抽象方法的参数列表有多少个 构造器重载怎么办呢

泛型推断可以该用哪个构造器

Supplier<Employee> s = Employee::new;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FRPnO5fl-1584371457819)(C:\Users\李嘉伟\AppData\Roaming\Typora\typora-user-images\image-20200316230624253.png)]

StreamAPI

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值