Java8(一)之走近Lamda

高阶函数

了解Lamda表达式之前,我们先来了解一下什么是高阶函数。
在数学和计算机领域中,高阶函数是至少满足以下两个条件中一个:
1.接受一个或多个函数作为输入
2.输出一个函数

为什么使用Lamda

相信大家除了Java语言也接触过类似于JavaScript或者Scala等脚本语言,这些语言是支持高阶函数的,也大都同时满足以上的两点。Scala语言本身就依赖于JVM,所以对于Java语言实现高阶函数也是完全,没有问题的。在JDK8中,Lamda表达式就是专门来实现Java的函数式编程。
可能有一些小伙伴还没有太多的使用JDK8的版本,就会想Lamda表达式能给我们带来什么呢?代码的简化以及可读性,Lamda表达式加链式调用会让代码看起来通俗易懂。话不多说,先看一个简单的栗子吧~

        // JDK8之前的代码
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread run!!!");
            }
        }).start();
        // Lamda表达式的代码
        new Thread(()->{System.out.println("thread run!!!");}).start();

在代码上的整洁程度来说显而易见,如果有了Lamda表达式我们很大程度上就可以告别恶心的匿名内部类(思考一下匿名内部类的特质,比如变量的可见性,Lamda表达式是怎样的,需要遵守么),尤其是有多次调用的情况,可以通过链式调用来表达,更加的条理和人性化。

如何申明一个Lamda表达式接口

1.申明一个接口,加入类注解@FunctionalInterface,保证接口中未实现的方法有且只有一个,接口默认方法不计算在内,如果不信的话,你可以试试,多个的话就会编译报错(这里需要思考一下为什么是一个,我个人觉得这里是Java为了实现函数式编程进行了“强扭的瓜”,的确是不太“甜”,内部的实现应该还是内部类的逻辑,这里是猜测)

@FunctionalInterface
public interface LamdaInterface {
    
    public String apply(String name);
    
    // 默认函数可以有
    default String addLastName(String name) {
        return apply(name) + "Curry";
    }

}

2.完成需要完成逻辑,就像填空题一样,所有的内容都完成了,只留下一个需要空来填,这要填的空就是要实现的函数逻辑。

public class NBAPlayer {
    
    public String firstName;

    // 具体结果还要依赖于接口方法的实现。这里就是我们要填的空
    public void printName(LamdaInterface lamdaInterface) {
        System.out.println(lamdaInterface.addLastName(this.firstName));
    }

}
  1. 根据Lamda表达式实现内容
    public static void main(String[] args) throws Exception{
        NBAPlayer nbaPlayer = new NBAPlayer();
        nbaPlayer.firstName = "Stephen";
        nbaPlayer.printName(name->name+"·");
    }

完整的步骤需要这三步,看到这里小伙伴们是不是觉得我忽悠你们了,这个写的代码感觉也不是很少呀,还是很痛苦。其实在实际开发的过程中,第1步是不需要我们自己做的,JDK在java.util.function包下有很多实例,涵盖了大部分的情况,所以不需要自己写函数式接口。大部分情况下第2步也是不需要自己做,因为大部分情况下都是去调用第三方的jar,这部分逻辑都已经实现,如果在一个团队中不是基础平台的开发人员的话,这一步接触的也比较少一点。所以对于我们来说其实只要把第三步完全掌握了就OK了。下面我们看一下JDK给我们提供的常见的函数式接口。

JDK提供的函数式接口

  1. Talk is cheap,show the code.
@FunctionalInterface
public interface Consumer<T> {
    void accept(T var1);

    default Consumer<T> andThen(Consumer<? super T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            this.accept(var2);
            var1.accept(var2);
        };
    }
}
  1. Talk is cheap,show the code.
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
  1. Talk is cheap,show the code.
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T var1);

    default Predicate<T> and(Predicate<? super T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            return this.test(var2) && var1.test(var2);
        };
    }

    default Predicate<T> negate() {
        return (var1) -> {
            return !this.test(var1);
        };
    }

    default Predicate<T> or(Predicate<? super T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            return this.test(var2) || var1.test(var2);
        };
    }

    static <T> Predicate<T> isEqual(Object var0) {
        return null == var0 ? Objects::isNull : (var1) -> {
            return var0.equals(var1);
        };
    }
}
  1. Talk is cheap,show the code.
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

上面的四种是我个人认为很常用的四种,就把JDK源码列出来了,大家看代码就好了,如果还需要其他形式的,建议先去java.util.function包下找一下,如果没有的话,再自己去新建。第一步搞定了,第二部其实主要就是实现的逻辑,没啥好说的,接下来看第三步的写法。

Lamda表达式常见写法

公共代码,下面会用到

@FunctionalInterface
interface inter1 {
    String said(String sm);
}

@FunctionalInterface
interface inter2{
    Employee getEmployee(String name, String address, int salary, int age);
}

class Robot{
    
    public String robotGun;
    
    public void attack (inter1 inter1) {
        String attack = inter1.said(robotGun);
        System.out.println(attack);
    }
}

class Attack{
    public static String attack(String said) {
        return "Attack!!!!!!!" + said;
    }
    
    public  String shot(String said) {
        return "Shot!!!!!!!" + said;
    }
    
    public Employee getEmployee(inter2 inter2,String name, String address, int salary, int age) {
        return inter2.getEmployee(name, address, salary, age);
    }
}
  1. 无参数,必须加括号,如果方法体的内容就一句话其实是可以不加花括号的
        Thread thread = new Thread(() -> {System.out.println(1);});
        thread.start();

2.一个参数,一个参数方法头可以省略括号

        Robot robot = new Robot();
        robot.robotGun = "AWM";
        robot.attack(said ->  said + " attack!");

3.多个参数,如果体部是一句话以上的必须加花括号

        List<Integer> list = Arrays.asList(99,55,66,88);
        Collections.sort(list, (x,y) -> x - y);
        for(Integer num : list) {
            System.out.println(num);
        }

4.引用静态方法

        Attack attack = new Attack();
        robot.attack(Attack::attack);

5.引用实例对象方法

        robot.attack(attack::shot);

6.引用构造方法

        inter2 inter2 = Employee :: new;
        Employee employee = attack.getEmployee(inter2, "xusq", "shanxi", 30000, 18);
        System.out.println(employee.toString());

以上我列出来的常见的Lamda表达式的写法,如果觉得不是很懂的话,就都忘了吧,你只需要记住,我们要传入的是一个函数就ok了,静态方法,成员方法,构造方法都是方法,只要是方法就去试试。
Lamda表达式的学习就到这里了,希望这篇文章能够帮助到一些小伙伴。求真至善,登崇俊良。我们下一期再见。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342