首页 > 其他分享 >JDK8新特性【接口新特征、lambda语法、Supplier、Consumer、Function、Predicate】

JDK8新特性【接口新特征、lambda语法、Supplier、Consumer、Function、Predicate】

时间:2024-06-14 23:31:17浏览次数:14  
标签:Function Predicate 接口 JDK8 println 返回值 out 方法 lambda

目录

一、关于接口的新特性

1.1 jdk1.8之前的接口重要特性

  • 方法全都是抽象方法,即都没有方法体

1.2 JDK8以后

  • 允许接口中有被default和static修饰的方法带方法体
代码演示

接口USB

public interface USB {
    /*
     * jdk8之前接口中只能有抽象方法
     * jdk8之后接口中被default的方法不是抽象方法,可以被重写,也可以不重写,不强制
     * 且方法还可以被static修饰,不能被重写,调用,只能通过接口调用
     */

    int a =1;
    void fun1();// 默认抽象方法
    default void funNew(){// 被default修饰方法
        System.out.println("JDK8新特性:default修饰的方法要有方法体,实现类不强制重写");
    }

    static void funNew2(){// 被static修饰方法
        System.out.println("JDK8新特性:static修饰的方法要有方法体,实现类不可重写,不可调用,通过接口直接调用");
    }
}

实现类USBImpl

public class USBImpl implements USB{
    @Override
    public void fun1() {
        System.out.println("重写旧方法");
    }

    @Override
    public void funNew() {  //可以重写default修饰的方法
    }

}

测试

public class USBImplTest {
    public static void main(String[] args) {

        USBImpl usb = new USBImpl();
        usb.fun1();
        usb.funNew();
        //usb.funNew2(); //实现类无法调用

        USB.funNew2();// 通过接口调用静态方法
    }
}

1.3 总结

通过代码演示发现
  • jdk8之后接口中被default的方法不是抽象方法,可以被重写,也可以不重写,不强制
  • 且方法还可以被static修饰,不能被重写,调用,只能通过接口调用
作用
  • 默认方法允许在不破坏现有实现的情况下向接口添加新功能。
  • 可以在不改变现有用户代码的情况下扩展接口。
  • 促进了API的演进,同时保持了向后的兼容性。

二、Lambda表达式[重点]

Lambda是匿名内部类的简化

Lambda 允许把函数(方法)作为一个方法的参数(函数作为参数传递到方法中)。


其实就是简化了匿名内部类的写法,更准确的说是对接口方法的重写的简化

2.1 将匿名内部类写法改写为lambda写法

使用lambda改写创建线程的方式

    public static void main(String[] args) {
        new Thread(new Runnable( ) {
            @Override
            public void run() {
                for (int i = 0; i < 10001; i++) {
                    System.out.println("正常实现Runnable完成线程" + i);
                }
            }
        }).start( );

        // 改成lambda形式
        // lambda是简化了匿名内部类,只剩下关于方法的参数列表和方法体
        // () -> {}
        new Thread(() -> {
            for (int i = 0; i < 10001; i++) {
                System.out.println("lambda完成线程"+i);
            }
        }).start( );

        // lambda是将方法当参数传递给另外一个方法
    }
}

2.2 语法特点

能够写成lambda形式的的前提
  1. 方法得有参数
  2. 参数的必须是接口
  3. 接口中的方法有且只能有一个!!!
语法特征

(参数) -> {执行语句}
或者
参数 -> 执行语句

  • 参数圆括号,当参数是一个的时候,圆括号可加可不加

    • (x) -> System.out.println(x)
    • x -> System.out.println(x)
  • 参数圆括号,当参数是多个的时候,圆括号必须加

    • (x,y) -> System.out.println(x+y)
  • 参数数据类型可写可不写,编译时会自动推断是什么类型

    • (x,y) -> System.out.println(x+y)
    • (int x,String y) -> System.out.println(x+y)
  • 执行语句的花括号,当且仅当执行语句只有一句时,可以不加花括号

    • new Thread(() -> System.out.println("匿名内部类开启线程")).start();
      
  • 执行语句的花括号,当执行语句不只一句时,必须加花括号

    • new Thread(() -> {
               int a = 1;
               a++;
               System.out.println("lambda开启线程" );
           }).start();
      
  • 关于返回值

    • 如果方法有返回值,且执行语句只有一行语句时,可以不用写return,直接写值

      test(() -> {return 1;});
      test(() -> 1);// 1就是return1
      
    • 如果代码比较多,又要返回数据,就必须写上return

      test(() -> {
      	int a = 1;
      	a++;
      	return a;
      });
      
代码演示
ppublic class lambdaTest {
	/*
	 1. **方法得有参数**
	 2. **参数的必须是接口**
	 3. **接口中的方法有且只能有一个!!!**
	*/
    public static void main(String[] args) {
        // 如果lambda方法体中只有一行代码,{}可以省略
        show1(() -> System.out.println("无参无返回值"));
        // 如果lambda方法体中有多行代码,{}不能省略
        show1(() -> {
            System.out.println("无参无返回值1");
            System.out.println("无参无返回值2");
            System.out.println("无参无返回值3");
        });
        /*
         * 有参数列表时,参数类型可以省略
         */
        // 只有一个参数,()可以省略
        show2(b1 -> System.out.println(b1 * 10));
        // 参数数量>1,()不可以省略
        show3((c1,c2)->System.out.println(c1 + c2));

        // 有返回值,但是只有一行代码,{}可以省略,return也可以省略,-> 跟的就是返回值
        show4(d -> d);


    }
	//接口IA为参数,IA只有一个方法
    static void show1(IA ia){
        ia.a();
    }
	//接口IB为参数,IB只有一个方法
    static void show2(IB ib){
        ib.b(1);
    }
    //接口IC为参数,IC只有一个方法
    static void show3(IC ic){
        ic.c(1,2);
    }
	//接口ID为参数,ID只有一个方法
    static void show4(ID id){
        id.d(10);
    }
}
// 接口:IA只有一个无参无返回值方法
interface IA{
    void a();  //无参无返回值
}

// 接口:IA只有两个个无参无返回值方法
interface IC{
    void c(int c1,int c2);  //参无返回值
}

// 接口:IA只有一个无参无返回值方法
interface IB{
    void b(int b);  //无参无返回值
}

// 接口:IA只有一个无参无返回值方法
interface ID{
    int d(int a);  //无参无返回值
}
深入理解lambda

为什么lambda要设计成,将方法(功能) 当参数传递给方法

  • 有了lambda,方法的功能不再局限,方法具体如何,要看看lambda功能如何
public class Demo3 {


    public static void main(String[] args) {
        double add = add(1, 2);
        System.out.println("add = " + add);

        double yunsuan = yunsuan((x, y) -> x / y, 1, 2);
        System.out.println("yunsuan = " + yunsuan);
    }

    /**
     * 已经的方法,参数列表是普通变量
     * 方法功能已经定好,唯一变化的是参数的值
     * 例如,这个add方法,是做两数相加,只能相加
     * 唯一能变的是,加的数不一样
     * --------------------------
     * 那如果,我想传入两个参数,让其相除返回结果?让其相乘返回结果?
     * 就需要重新设计方法
     */
    public static double add(int a,int b){
        return a + b;
    }


    /**
     * 有了lambda之后,方法的执行功能就不再固定
     * 如何运行,要看调用时,传入的lambda是如何运行的
     */
    public static double yunsuan(IE e,int a,int b){
        return e.jisuan(a, b);
    }

}
interface IE {
    double jisuan(int a,int b);
}

2.3 总结

  • 其实 () -> {}
    • ()里面放的是重写方法的参数
    • {}里面放的是重写方法的方法体
    • 上面各种写法只是在特定情况下的简写,没有特定条件是没法简写的,就要按部就班来
  • lambda就是简化了匿名内部类的写法
  • lambda其实就是接口方法的重写
  • lambda的参数和返回值是根据接口方法决定的

三、函数式接口

3.1 概念

什么是函数式接口

接口中只有一个抽象方法时,该接口就是函数式接口.

Java提供了一个注解可以校验接口是否是函数式接口

@FunctionalInterface

Java中提供了几个特别常用的函数式接口

  • Supplier 供应,即返回一个数据 (无参有返回值的方法)
  • Consumer 消费,即给其传入数据做运算 (有参无返回值的方法)
  • Function 函数,传入2个参数,用于转换数据的 (有参有返回值的方法)
  • Predicate 判断,返回时boolean (有参,返回值是boolean)

四个典型的函数式接口

3.2 Supplier

  • Supplier.java源码
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}
// 该接口用来返回一个数据,所以叫供应商
// 其实就是无参数有返回值的接口,用的时候就是无参有返回值的lambda

练习,设计方法,通过Supplier接口,获得字符串的长度

		/*
         * Supplier接口 ---顾名思义:供应,提高
         *  提供的方法--- T get();
         *  不需传入参数,就有返回值
         */
        //利用Supplier接口,实现获得字符串长度功能
        int i = get(() -> "java".length());
        System.out.println("i = " + i);// i = 4
  	
  	//参数为Supplier接口的方法
    public static int get(Supplier<Integer> supplier){
        return supplier.get();
    }

3.3 Consumer

JDK中Consumer.java源码

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     * 给传入一个值,对该值进行操作
     * @param t the input argument
     */
    void accept(T t);
}
// 其实就是有参数无返回值的接口,用的时候就是有参无返回值的lambda

练习:设计方法,传入字符串,将字符串全部转大写,后输出

 		/*
         * Consumer接口 ---顾名思义:消费,消耗
         *  提供的方法--- void accept(T t);
         *  需传入参数,无返回值
         */
        //利用Consumer接口,实现字符串转大写功能
        String s = "java";
        accept(c -> System.out.println(c.toUpperCase()),s);// JAVA

    //参数为Consumer接口的方法
    public static void accept(Consumer<String> consumer,String s){
        consumer.accept(s);
    }

3.4 Function

JDK中Function.java源码

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}
// 该接口用于,转换数据
// 其实就是有参数有返回值的接口,用的时候就是有参有返回值的lambda

利用Function,实现字符串数字转为整形数字功能

	 	/*
         * Function<T, R>接口 ---顾名思义:函数,功能
         *  提供的方法--- R apply(T t);
         *  将T转换乘R类型 ,即转换数据
         */
        //利用Function,实现字符串数字转为整形数字功能
        String s2 = "111";
        Integer apply = apply(f -> Integer.parseInt(f), s2);
        System.out.println("apply = " + apply);// apply = 111
  	
   //参数为Function接口的方法
    public static Integer apply(Function<String,Integer> function,String s){
        return function.apply(s);

    }

3.5 Predicate

JDK中Predicate.java源码

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

判断数据是否是偶数

   /*
         * Predicate接口 ---顾名思义:判断,断定
         *  提供的方法--- boolean test(T t);
         *  提供判断方法
         */
        //利用Predicate接口,实现判断是否时偶数功能
        int i1 = 2;
        boolean b = predicate(a -> a % 2 == 0, i1);
        System.out.println("b = " + b); // b = true

    //参数为Predicate接口的方法
    public static boolean predicate(Predicate<Integer> predicate,Integer integer){
        return predicate.test(integer);
    }

3.6 总结

  • Supplier接口的方法一般用于 获得数据
  • Consumer接口的方法 一般用于 处理数据
  • Function接口的方法一般用于 转换数据
  • Predicate接口的方法一般用于 判断数据

思维导图

在这里插入图片描述


最后

如果感觉有收获的话,点个赞

标签:Function,Predicate,接口,JDK8,println,返回值,out,方法,lambda
From: https://blog.csdn.net/m0_73940426/article/details/139652063

相关文章

  • G. D-Function
    原题链接题解先不考虑k的限制,而是考虑对于任意一个数,存不存在一个k使得题目所给等式成立当\(n·k\)没有进位时,等式一定成立(赛时也许想到这就够了)假如有进位呢?对于任何一个位数大于1的数,必有\(D(n)\ltn\)(想想十进制是怎么表示数的)而对于位数为1的数,有\(D(n)=n\)所......
  • JDK8新特性之Lambda表达式
    Lambda,音标[ˈlamdə],中文翻译“拉姆达”,第11个希腊字母λ(大写Λ)。1.引入原因JDK8引入Lambda表达式是为了简化匿名类相关代码。当接口比较简单,只有一个方法时,我们也不得不写许多无关业务的代码来实现匿名类。而Lambda表达式却允许将功能(functionality)视作方法参数或者视代......
  • 【Java之JDK8新特性】
    文章目录一、Java8中的Lambda表达式如何改善Java代码?二、在Java8中,接口有哪些新特性?三、如何使用Java8的StreamAPI进行集合处理?四、Java8的Optional类有什么用途?五、Java8中Date-TimeAPI的改进有哪些?六、Java8中的方法引用是什么,它有什么好处?七、Java8中的Compl......
  • E - Reachability in Functional Graph
    E-ReachabilityinFunctionalGraphhttps://atcoder.jp/contests/abc357/tasks/abc357_e 思路概念:基环树-内生树。https://www.cnblogs.com/Dfkuaid-210/p/14696378.html方法:使用拓扑排序,从入度为0的点开始,依此从外层向内层拆点,直到剩下环,拆换过程中把拆掉的size记到......
  • 翻译《The Old New Thing》- Why isn’t there a SendThreadMessage function?
    Whyisn'tthereaSendThreadMessagefunction?-TheOldNewThing(microsoft.com)https://devblogs.microsoft.com/oldnewthing/20081223-00/?p=19743RaymondChen 2008年12月23日为什么没有SendThreadMessage函数?简要文章讨论了Windows中不存在`SendThread......
  • GLM-4-9B领先!伯克利函数调用榜单BFCL的Function Calling评测方法解析与梳理
    智谱公布的GLM-4-9B基于BFCL榜单的工具调用能力测试结果©作者|格林来源|神州问学在智谱最新开源的GLM-4-9B-Chat中,其工具调用能力在BFCL(伯克利函数调用排行榜)榜上获得了超高的总BFCL分,和gpt-4-turbo-2024-04-09几乎不相上下。在榜单中,还提到了AST总分以及Exec总分两个......
  • 在 Jupyter 编辑函数(Edit function in Jupyter)
    在JupyterNotebook里编辑一个已经存在的函数是可以实现的。你需要重新定义这个函数并执行该单元格。这将覆盖之前的定义,使用新的代码。例如,如果你有一个函数fetch_california_housing,你可以按照以下步骤编辑和重新定义它:找到该函数的定义单元格,或者创建一个新的单元格......
  • js 中 (function($){...})(jQuery) 含义
    原文链接:https://www.cnblogs.com/Jeely/p/10715089.htmljs中(function($){...})(jQuery)含义js中定义函数常用写法是functionname(arg){//arg则是匿名函数的参数。//...}调用函数时的写法是:name(arg);======================================================......
  • 'scanf': This function or variable may be unsafe. Consider using scanf_s instead
    在C++中使用scanf时应注意两点1.导入#include<cstdio>2.将scanf改成scanf_s  VS2022实现查找替换编辑——》查找和替换——》在文件中替换 输入要查找替换的名称 点击全部替换完成......
  • css45 CSS Math Functions
    https://www.w3schools.com/css/css_math_functions.asp TheCSSmathfunctionsallowmathematicalexpressionstobeusedaspropertyvalues.Here,wewillexplainthecalc(),max()andmin()functions.Thecalc()FunctionThecalc()functionperformsac......