当前位置: 首页 > article >正文

Java研学-Lambda表达式

一 Lambda表达式 – 箭头函数

1 含义

  JDK8首次将函数式编程引入到Java代码中;这是一种新型的方法参数传递的方式;直接将获取参数的步骤传递给需要该参数的方法中–Lambda表达式

2 特点

  1 简化代码

  2 多核友好

  3 面向对象思想不足

public class Play {
    public static void main(String[] args) {
        // 实现Runnable的优势在于他避免了单继承的局限性,但需要通过Thread构造器将实现接口的对象传给Thread
        // 多线程输出 匿名内部类实现run方法,通过Thread类调用start开启
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("多线程操作");
            }
        }).start();
        System.out.println("等价于");
        new Thread(()-> System.out.println("新多线程操作")).start();
    }
}

3 例子-自定义水果类,以普通方式与Lambda分别实现

自定义水果类

// 注解需导入lombok
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Fruit {
    private Long id;        // 编号
    private String name;    // 水果名
    private Integer price;  // 单价
}

普通方法

public class FruitTest {
    // 创建水果集合
    private static List<Fruit> fruits=new ArrayList<>();
    // 水果只需存储一次,进入直接初始化
    static {
        fruits.add(new Fruit(1L,"猕猴桃",6));
        fruits.add(new Fruit(2L,"苹果",5));
        fruits.add(new Fruit(3L,"苹果梨",4));
        fruits.add(new Fruit(4L,"橙子",7));
        fruits.add(new Fruit(5L,"草莓",6));
        fruits.add(new Fruit(6L,"山竹",11));
    }

    public static void main(String[] args) {
        // 查询所有6块钱的水果
        findByPrice();
        // 查询含苹果名字的水果
        findByName();
    }

    private static void findByPrice(){
        List<Fruit> prices=new ArrayList<>();
        for (Fruit f:fruits) {
            if(f.getPrice()==6){
                prices.add(f);
            }
        }
        System.out.println(prices);
    }

    private static void findByName(){
        List<Fruit> names=new ArrayList<>();
        for (Fruit f:fruits) {
            if(f.getName().contains("苹果")){
                names.add(f);
            }
        }
        System.out.println(names);
    }
}

Lambda

// 自定义接口
@FunctionalInterface
public interface IFruit {
    // 接口中定义统一操作规则 根据指定商品信息判断是否满足需求
    boolean test(Fruit f);
}

// 使用
public class FruitTest {
    // 创建水果集合
    private static List<Fruit> fruits=new ArrayList<>();
    // 水果只需存储一次,进入直接初始化
    static {
        fruits.add(new Fruit(1L,"猕猴桃",6));
        fruits.add(new Fruit(2L,"苹果",5));
        fruits.add(new Fruit(3L,"苹果梨",4));
        fruits.add(new Fruit(4L,"橙子",7));
        fruits.add(new Fruit(5L,"草莓",6));
        fruits.add(new Fruit(6L,"山竹",11));
    }
    // 通过匿名内部类改造Lambda实现接口
    public static void main(String[] args) {
        // 查询所有6块钱的水果
        findFruitByI((p)->p.getPrice()==6);
        // 查询含苹果名字的水果
        findFruitByI(p->p.getName().contains("苹果"));

    }

    private static void findFruitByI(IFruit ifr){
        List<Fruit> ff =new ArrayList<>();
        for (Fruit f:fruits) {
            if(ifr.test(f)){
                ff.add(f);
            }
        }
        System.out.println(ff);
    }
}

4 Lambda表达式格式

  Lambda的固定格式核心符号是 ->
  左侧:表示通过Lambda表达式改造方法的参数部分
  右侧:表示通过Lambda表达式进行改造的方法的方法体

5 Lambda表达式改造前提

  必须是接口,并且接口中有且仅有一个抽象方法,为保证接口中只定义一个抽象方法,JDK8提出使用@FunctionaIInterface(函数式接口)

@FunctionalInterface
public interface IFruit {
    // 接口中定义统一操作规则 根据指定商品信息判断是否满足需求
    boolean test(Fruit f);
}

6 Lambda表达式特点演示

public class FruitTest {
	......
    public static void main(String[] args) {
        // ① 没有特殊要求改造方法的参数类型可以省
        List<String> list= Arrays.asList("大黄","大白","小黑");
        // foreach类似增强for
        list.forEach(s-> System.out.println(s));
        // ② 改造方法仅有一个参数时()可以省,没有参数或有多个参数时()不能省
        new Thread(()-> System.out.println("多线程启动")).start();
        // 实例化时通过代码块为map赋值
        Map<String,String> map=new HashMap<String,String>(){
            {
                this.put("大黄","15kg");
                this.put("大白","12kg");
            }
        };
        // ③ 改造方法仅有一条代码{}与;都可以省去,若有多条代码则不能省去,一般改造方法只有一条代码
        map.forEach((k,v)->{
            System.out.println(k);
            System.out.println(v);
        });
        // ④ 改造方法仅一条代码,且为return语句时,return关键字可省去
        findFruitByI(new IFruit() {
            @Override 
            public boolean test(Fruit f) {
                return f.getPrice()==6;
            }
        });
        findFruitByI(p->p.getPrice()==6);
    }
    private static void findFruitByI(IFruit ifr){
        List<Fruit> ff =new ArrayList<>();
        for (Fruit f:fruits) {
            if(ifr.test(f)){
                ff.add(f);
            }
        }
        System.out.println(ff);
    }
}

7 常见函数式接口

函数式接口参数类型返回类型说明
Consumer< T>消费型接口Tvoid对类型为T的对象进行操作,方法:void accept(T t)
Supplier< T>供给型接口T返回类型为T的对象 方法:T get();(可做工厂)
Function< T,R>函数型接口TR对类型为T的对象进行操作,并且返回结果是R类型(任意数据类型),方法:R apply(T t);
Predicate< T>断言型接口Tboolean判断类型为T的对象是否满足条件,返回值固定为布尔类型,方法 boolean test(T t)
public class FunctionPlay {
    // 创建水果集合
    private static List<Fruit> fruits = new ArrayList<>();

    // 水果只需存储一次,进入直接初始化
    static {
        fruits.add(new Fruit(1L, "猕猴桃", 6));
        fruits.add(new Fruit(2L, "苹果", 5));
        fruits.add(new Fruit(3L, "苹果梨", 4));
        fruits.add(new Fruit(4L, "橙子", 7));
        fruits.add(new Fruit(5L, "草莓", 6));
        fruits.add(new Fruit(6L, "山竹", 11));
    }

    public static void main(String[] args) {
        buy(36, new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) {
                System.out.println("买了"+integer+"元的水果");
            }
        });
        buy(456,(consumer)-> System.out.println("买了"+consumer+"元的水果"));

        int it=getRealLength("playthis", new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return s.length();
            }
        });
        System.out.println(it);
        System.out.println(getRealLength("playthis",s -> s.length()));

        System.out.println(getCode(6, new Supplier<Integer>() {
            @Override
            public Integer get() {
                return (int)(Math.random()*10);
            }
        }));
        System.out.println(getCode(8,()->(int)(Math.random()*10)));

        isOk(new Predicate<Fruit>() {
            @Override
            public boolean test(Fruit fruit) {
                return fruit.getPrice()>8;
            }
        });
    }

    // 购买消费金额
    public static void buy(int moeny,Consumer<Integer> consumer){
        // 接口对象consumer调用方法accept传递参数moeny
        consumer.accept(moeny);
    }
    // 获取长度(String真实长度)
    public static int getRealLength(String let, Function<String,Integer> fun){
        return fun.apply(let);
    }
    // 返回指定位数随机码
    public static String getCode(int num, Supplier<Integer> sup){
        // 创建StringBuffered
        StringBuffer sb=new StringBuffer();
        for (int i = 0; i < num; i++) {
            sb.append(sup.get());
        }
        return sb.toString();
    }
    // 判断水果是否超过8元
    public static void isOk(Predicate<Fruit> fp){
        for (Fruit f:fruits) {
            if(fp.test(f)){
                System.out.println(f.toString());
            }
        }
    }
}

8 方法引用

① 普通调用方法的方式

  对象.方法名([参数])

  类名.方法([参数])–必须被static修饰

② 方法引用

  进行Lambda表达式改造后,传递的操作已定义完毕(Java核心类库提供或者是其他程序员定义好的方法),可使用方法引用的方式调用

③ 方法引用的前提

  引用的方法必须是定义好的,必须是Lambda表达式改后的方法

④ 格式-- ::(引用运算符,两个引号)

::左侧 – 通过什么方式引用的即 对象名或类名

::右侧 – 调用方法的名字(方法引用只能引用无参方法,故不能写())

public class PlayMethod {
    public static void main(String[] args) {
        // 对象::方法名
        fun1();
        // 类名::静态方法
        fun2();
        // 类名::方法
        fun3();
        // 类名::new
        fun4();
    }
    // 方法引用有局限性,调用定义好的方法不能灵活应用
    // list.forEach(p-> System.out.println(p));
    private static void fun1(){
        List<String> list= Arrays.asList("大黄","大白","小黑");
        list.forEach(System.out::print);
    }
    // ()->Math.random()
    private static void fun2(){
        Supplier sup=Math::random;
        // get方法获取值
        System.out.println(sup.get());
    }
    // s->s.length()
    private static void fun3(){
        Function<String,Integer> fun=String::length;
        System.out.println(fun.apply("8537矿泉水"));
    }
    // 类名::new 构造器引用
    private static void fun4(){
        /*Supplier<String> sup=new Supplier<String>() {
            @Override
            public String get() {
                return new String();
            }
        };*/
        // ()->new String();
        Supplier<String> sup=String::new;
        System.out.println(sup.get());
    }
}

9 延迟执行

又称延迟加载或懒加载

public class PlayMethod {
    public static void main(String[] args) {
        String name="大黄";
        String is="是";
        String color="黄色的";
        // 拼接 无论是否满足条件此刻都已经完成拼接存放在工具中了(性能浪费),满足条件才提供结果
        addString("ok",name+is+color);
    }
    private static void addString(String info, String s) {
        if("ok".equals(info)){
            System.out.println(s);
        }
    }
}

使用供给型接口实现延迟加载

public class PlayMethod {
    public static void main(String[] args) {
        String name="大黄";
        String is="是";
        String color="黄色的";
        // 拼接
        /*addString("no", new Supplier<String>() {
            @Override
            public String get() {
                return name+is+color;
            }
        });*/
        addString("ok",()->name+is+color);
    }
    private static void addString(String info, Supplier<String> sup) {
        if("ok".equals(info)){
        // 判断通过才拼接字符串
            System.out.println(sup.get());
        }
    }
}

10 接口的多继承

① 接口能够定义的类成员

  成员常量:public static final 数据类型 常量名=值;

  抽象方法: 返回 方法名([参数]);

  JDK8后,在接口中可定义default和static方法,能够具有方法体

② 代码演示
定义接口A,包含抽象方法fun1()的default方法fun2(),以及static方法fun3();

public interface A {
    void fun1();
    default void fun2(){
        System.out.println("Afun2");
    }
    static void fun3(){
        System.out.println("Afun3");
    }
}

定义接口B,包含default方法fun2(),以及static方法fun3();


C类分别实现AB两个接口

public class C implements A,B{
    @Override
    public void fun1() {

    }
    // 一个类实现多个接口时,若接口中default方法同名
    // 需重写default方法确认调用哪个default方法
    @Override
    public void fun2() {
        B.super.fun2();
    }
}

http://www.kler.cn/a/162029.html

相关文章:

  • IEC60870-5-104 协议源码架构详细分析
  • 【Vue】Vue3.0(二十一)Vue 3.0中 的$event使用示例
  • 字节、快手、Vidu“打野”升级,AI视频小步快跑
  • Linux第四讲:Git gdb
  • 分享一个傻瓜式一键启动的加速器
  • 网页web无插件播放器EasyPlayer.js点播播放器遇到视频地址播放不了的现象及措施
  • Python函数默认参数设置
  • C语言验证哥德巴赫猜想
  • AttributeError: module ‘importlib_resources‘ has no attribute ‘path‘ 解决方案
  • cpu 300% 爆满 内存占用不高 排查
  • 【AIGC】prompt工程从入门到精通
  • 专业130+总分400+云南大学通信847专业基础综考研经验(原专业课827)
  • 获取拼多多京东淘宝商品数据店铺数据店铺信息最推荐最好用的一种方式就是API接口
  • HTTPS加密协议:保护你的网络安全
  • ArcGIS Pro中怎么设置标注换行
  • yum源不起作用_yum无法安装程序_Linux默认源替换---Linux工作笔记067
  • YOLOv7独家最新改进《全网无重复》感知聚合SERDetect检测头:高效涨点,即插即用|检测头新颖改进
  • type property can‘t be changed 报错问题解决
  • Matlab 点云对称性检测
  • kyuubi整合flink yarn application model
  • Java + Selenium + Appium自动化测试
  • ELK(四)—els基本操作
  • 如何将 MySQL 数据库转换为 SQL Server
  • 基于个微机器人的开发
  • pycharm中debug,py文件
  • C#winform点击按钮下载数据库中表的字段到Excel上