前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java之Lambda表达式与方法引用实战

Java之Lambda表达式与方法引用实战

作者头像
用户5224393
发布2019-08-13 15:49:34
5010
发布2019-08-13 15:49:34
举报
文章被收录于专栏:Java研发军团Java研发军团
作者:yangbishang 原文:https://blog.csdn.net/qq_36582604/article/details/81393732

1.Lambda

从JDK1.8开始为了简化使用者进行代码开发,专门提供有Lambda表达式的支持,利用此操作形式可以实现函数式的编程,对于函数式编程比较著名的语言:haskell,Scala,利用函数式的编程可以避免掉面向对象编程之中的一些繁琐的问题。

面向对象在其长期发展的过程中一直有一部分的反对者认为面向对象过于繁琐

比如:

public interface IMessage {
    public void send(String str);
}

public class Demo {
    public static void  main(String args[]){
        IMessage msg = new IMessage() {
            @Override
            public void send(String str) {
                System.out.println("消息发送:"+str);
            }
        };
        msg.send("hahahaha");
    }
}

上面语句的核心功能只有一行核心语句,但是为了这一行核心语句依然需要按照完整的面向对象给出的设计结构进行开发。所以Lambda出现啦。

public interface IMessage {
    public void send(String str);
}

public class Demo {
    public static void  main(String args[]){
       IMessage msg = (str)->{
           System.out.println("发送消息:"+str);
       };
        msg.send("hahahaha");
    }
}

简单吧,这种形式就避免了复杂的面向对象结构化的要求。

Lambda表达式如果要想使用,那么必须有一个重要的实现要求:SAM(Single Abstract Method)只有一个抽象方法(但可以有default和static方法)。

以IMessage接口为例,在这个接口里面发现只是提供有一个send()方法,除此之外没有任何其他方法定义,所以这样的接口就被称为函数式接口,而只有函数式接口才可以被Lambda表达式所使用

jdk1.8之后可以在接口里面定义static方法和default方法也是为了函数式编程而设置的,如下面这个是允许的

public interface IMessage {
    public void send(String str);
    public default void defaultMethod(){
        System.out.println("hahahaha");
    };
}

public class Demo {
    public static void  main(String args[]){
       IMessage msg = (str)->{
           System.out.println("发送消息:"+str);
       };
        msg.send("hahahaha");
        msg.defaultMethod();
    }
}

对于Lambda表达式而言,提供了如下几种格式

1) 方法没有参数:()-->{ };

2) 方法有参数:(参数,参数)-->{ };

3) 如果现在只有一行语句返回:(参数,参数)-->语句;

我们看下第三种

public interface IMath {
    public int add(int x,int y);
}

public class Demo {
    public static void  main(String args[]){
       IMath math = (t1,t2) -> t1 + t2;
        System.out.println(math.add(10,20));
    }
}

利用Lambda表达式可以使代码更加简便

其中一个很经典的应用就是多线程Runnable接口的例子

public class Test{
    public static void main(String[] args) {
        /*
        匿名内部类的方式
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("nihao");
            }
        }).start();
        System.out.println("你好");
        */

        //lambda的方式
        new Thread(()-> {
            for(int i = 1 ; i<100 ; i++){
                System.out.println("It is a lambda function!");
            }
        }).start();
    }
}

2.方法引用

引用数据类型最大的特点是可以进行内存的指向处理,但是在传统的开发之中一直所使用的只是对象引用操作。

而jdk1.8以后也提供有方法的引用,即:不同的方法名称可以描述同一个方法(即可以为一个方法定义多个名字,但是要求必须是函数式接口)。如果要进行方法的引用在java里面提供了如下的四种形式

1)引用静态方法: 类名称 :: static方法名称;

2)引用某个实例对象的方法: 实例化对象 :: 普通方法;

3)引用特定类型的方法: 特定类 :: 普通方法;

4)引用构造方法: 类名称 :: new ;

2.1 引用静态方法:

在String类里面提供有String.valueOf( )方法,这个方法就属于静态方法。

方法范例:public static String valueOf(int i).该方法有参数还有返回值

@FunctionalInterface  //函数式接口
public interface IFunction<P,R> {
    public R change(P p);      //p描述的是参数,R描述的是返回值
}

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

        IFunction<Integer , String > fun = String :: valueOf;
        String str = fun.change(100);
        System.out.println(str.length());
    }
}

输出结果为:3

2.2 引用某个实例对象的方法

String类里面有个转大写的方法: public String toUpperCase( )

这个方法是必须在有实例化对象提供的情况下才可以调用

@FunctionalInterface  //函数式接口
public interface IFunction<R> {
    public R upper();
}

public class Demo {
    public static void  main(String args[]){
        IFunction<String> fun = "hahaha" :: toUpperCase;    //"hahaha"为String的实例化对象
        System.out.println(fun.upper());
    }
}

输出结果为:hahaha

2.3 引用特定类型的方法

在方法引用时也可以引用特定类中的一些操作方法,在String里面提供有一个字符串大小关系的比较

比较大小:public int compareTo(String anotherString)

这是一个普通方法,如果要引用普通方法,则往往都需要实例化对象,但是如果说现在你不想给出实例化对象,只是想引用这个方法,则就可以使用特定类来进行引用处理。

@FunctionalInterface  //函数式接口
public interface IFunction<P> {
    public int compare(P p1,P p2);
}

public class Demo {
    public static void  main(String args[]){
        IFunction<String> fun = String :: compareTo ;    //String类中的conpareTo方法
        System.out.println(fun.compare("A","a"));
    }
}

输出结果为:-34

2.4 引用构造方法

public class Person {
    private String name;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return "姓名:" + this.name + "、年级:" + this.age ;
    }
}

@FunctionalInterface  //函数式接口
public interface IFunction<R> {
    public R create(String s ,int a);
}

public class Demo {
    public static void  main(String args[]){
        IFunction<Person> fun = Person :: new ;    //String类中的conpareTo方法
        System.out.println(fun.create("张三",20));
    }
}

输出结果:姓名:张三、年级:20

提供方法引用的概念更多情况下也只是弥补了对于引用的支持功能。

3 内建函数式的接口

在jdk1.8之中提供有Lambda表达式,也提供有方法引用,但是你会发现现在如果由开发者自己定义函数式接口,往往都需要使用“@FunctionalInterface”注解来进行大量申明,于是很多的情况下如果为了方便则可以直接引用系统中提供的函数式接口。

在系统之中专门提供了一个java.util.function的开发包,里面可以直接使用函数式接口。在这个包下面一共有如下几个核心接口供使用。

1.功能型函数式接口:有输入有返回(例如:在String类中有一个方法判断是否以指定的字符串开头)

接口定义:

@FunctionalInterface
public interface Function<T,R>{
    public R apply(T t);
}

接口的使用:

import java.util.function.Function;
public class Test {
    public static void main(String[] args) {
        Function<String,Boolean> fun = "**Hello" ::  startsWith;
        System.out.println(fun.apply("**"));
    }
}

输出:true

2.消费型函数式接口:只能够进行数据的处理操作,而没有任何返回(例如:在进行系统数据输出的时候使用的是:System.out.println())

接口定义:

@FunctionalInterface
public interface Consumer<T>{
    public void accept(T t);
}

接口的使用:

import java.util.function.Consumer;
public class Test {
    public static void main(String[] args) {
        Consumer<String> con = System.out ::  println;
        con.accept("hahaha");
    }
}

输出:hahaha

3.供给型函数式接口:没有传入参数,但是有返回值(例如:在String类中提供有转小写方法,这个方法没有接受参数,但是有返回值:toLowerCase())

接口定义:

@FunctionalInterface
public interface Supplier<T>{
    public T get();
}

接口使用:
import java.util.function.Supplier;
public class Test {
    public static void main(String[] args) {
        Supplier<String> sup = "hahaha" :: toLowerCase ;
        System.out.println(sup.get());
    }
}

输出:hahaha

4.断言型函数式接口:进行判断处理(例如:在String类有一个equalsIgnoreCase()方法)

接口定义:

@FunctionalInterface
public interface Predicate<T>{
    public boolean test(T t);
}

接口的使用:

import java.util.function.Predicate;
public class Test {
    public static void main(String[] args) {
        Predicate<String> pre = "YY" :: equalsIgnoreCase ;
        System.out.println(pre.test("yy"));
    }
}

输出:true

以后对于实际项目开发之中,如果JDK本身提供的函数式‘接口可以被我们所使用,那么就没有必要进行重新定义了

类型的文章可以多多留言,小编会尽量搜集,谢谢!!!

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java研发军团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.Lambda
  • 2.方法引用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档