热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JAVA8核心语法梳理(1)Lambda表达式、函数式接口、方法引用

建议收藏方便


JAVA前线 


互联网技术人思考与分享,欢迎长按关注


1 文章概述

JAVA13已经面世一段时间了,但是追根溯源一些新特性例如Lambda表达式、函数式接口、StreamAPI首次还在是出现在JAVA8。这些新特性有些开发者使用并不习惯,尤其链式编程感觉没有代码断句,可读性不强。但是JAVA8之所以逐渐流行确实是因为确实有许多优点:

  • 代码优雅
  • 易于并行
  • StreamAPI
  • Optional减少空指针

现在项目代码中越来越多出现JAVA8语法,为了读懂代码也需要我们熟悉JAVA8语法,本文介绍JAVA8如下重要特性,streamAPI我们下一篇文章再详细介绍。

  • Lambda表达式
  • 函数式接口
  • 方法引用

2 Lambda表达式

2.1 基本说明

Lambda表达式本质上是一个匿名函数,我们可以将一个Lambda表达式像参数一样进行传递。

public static void test01() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("公众号JAVA前线");
        }
    }).start();

    /** Lambda表达式 **/
    new Thread(() -> System.out.println("公众号JAVA前线")).start();
}

我们看到Lambda表达式将6行代码缩短为1行,代码简洁而优雅,但是仅仅看代码并不好理解,下面我们介绍Lambda语法。

2.2 语法详解

Lambda表达式引入了->箭头操作符,箭头操作符左边指定表达式参数,右表是表达式执行体,下面我们根据参数个数的不同说明Lambda表达式语法。

(1) 无参数

public static void test02_NoParam() {
    Runnable task = () -> System.out.println("公众号JAVA前线");
    new Thread(task).start();
}

(2) 一个参数

单个参数可以不写小括号。假设一个方法参数类是字符串,在写Lambda表达式时并不要显示申明String类型,编译器可以根据上下文推断出类型,这就是类型推断。

import java.util.function.Consumer;

public static void test03_OneParam() {
    Consumer c1 = (str) -> System.out.println(str);
    c1.accept("公众号JAVA前线");
    Consumer c2 = str -> System.out.println(str);
    c2.accept("公众号JAVA前线");
}

上述例子使用了函数式接口Consumer,下一个章节我们再介绍。

(3) 多个参数

如果Lambda体只有一行代码则花括号和return可以省略。

public class Student {
    private int age;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public static void test04_MultiParam() {
    List list = new ArrayList();
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> {
        return o1.getAge().compareTo(o2.getAge());
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
}


3 函数式接口

函数式接口特点只包含了一个方法。JAVA8有四大内置函数式接口,其它内置函数式接口,还可以自定义函数式接口。

3.1 四大内置函数式接口

接口名输入类型输出类型
Consumer[T]Tvoid
Supplier[T]voidT
Function[T,R]TR
Predicate[T]Tboolean

(1) Consumer

Consumer作为消费型接口输入类型为T,没有输出类型,核心方法accept(T)

import java.util.function.Consumer;

public static void testConsumer() {
    Consumer consumer = (str) -> {
        String newStr = "公众号" + str;
        System.out.println(newStr);
    };
    consumer.accept("JAVA前线");
}

(2) Supplier

Supplier作为供给型接口没有输入类型,输出类型为T,核心方法T get()

import java.util.function.Supplier;

public static void testSupplier() {
    Supplier supplier = () -> {
        return "公众号JAVA前线";
    };
    String result = supplier.get();
    System.out.println(result);
}

(3) Function

Function作为函数型接口输入类型为T,输出类型为R,核心方法R apply(T)

import java.util.function.Function;

public static void testFunction() {
    Function function = (str) -> {
        if("公众号JAVA前线".equals(str)) {
            return 1;
        }
        return 0;
    };
    Integer result = function.apply("公众号JAVA前线");
    System.out.println(result);
}

(4) Predicate

Predicate作为判断型接口输入类型为T,输出类型为boolean,核心方法boolean test(T)

import java.util.function.Predicate;

public static void testPredicate() {
    Predicate predicate = (str) -> {
        if ("公众号JAVA前线".equals(str)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    };
    boolean result = predicate.test("公众号JAVA前线");
    System.out.println(result);
}

3.2 自定义函数式接口

FunctionalInterface标识一个自定义函数式接口,我们可以根据需求自定义函数式接口。

/**
 * 自定义函数接口
 *
 * @author 公众号JAVA前线
 *
 * @param  输入类型1
 * @param  输入类型2
 * @param  输出类型
 */

@FunctionalInterface
public interface MyInterfaceFunction<TRU{
    public U bizMethod(T t, R r);
}

public class Java8_Function {
    public static void testMyFunction() {
        MyInterfaceFunction myFuntion = (str1, str2) -> {
            if ("公众号".equals(str1) && "JAVA前线".equals(str2)) {
                return 1;
            }
            return 0;
        };
        Integer result = myFuntion.bizMethod("公众号""JAVA前线");
        System.out.println(result);
    }
}

3.3 其它内置函数式接口

在四大内置函数式接口基础上,JAVA8提供了其它内置函数式接口,我们尝试列出一些并选择编写几个代码实例。

接口名输入类型输出类型
BiConsumerT、Uvoid
BiFunctionT、UR
UnaryOperatorTT
BinaryOperatorT、TT
ToIntFunctionTint
(1) BiFunction

BiFunction是Function函数增强版,允许两种输入类型

import java.util.function.BiFunction;

public static void testBiFunction() {
    BiFunction biFunction = (str1, str2) -> {
        if ("公众号".equals(str1) && "JAVA前线".equals(str2)) {
            return 1;
        }
        return 0;
    };
    Integer result = biFunction.apply("公众号""JAVA前线");
    System.out.println(result);
}

(2) BiConsumer

BiConsumer是Consumer函数增强版本,允许两种输入类型

import java.util.function.BiConsumer;

public static void testBiConsumer() {
    BiConsumer biConsumer = (str1, str2) -> {
        System.out.println(str1 + str2);
    };
    biConsumer.accept("公众号""JAVA前线");
}

(3) BinaryOperator

对类型为T的数据进行二元运算,并返回类型为T的结果

import java.util.function.BinaryOperator;

public static void testBinaryOperator() {
    BinaryOperator biOperator = (str1, str2) -> {
        return str1 + str2;
    };
    String result = biOperator.apply("公众号""JAVA前线");
    System.out.println(result);
}


4 方法引用

方法引用语法操作符是两个冒号,初看会让人比较费解。本章节我们来分析这个语法。当我们在编写Lambda方法体时,如果方法体的方法已经有实现,那么我们可以直接引用这个方法,这就是方法引用,需要注意的是参数列表必须一致。方法引用语法有四类:

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类::new

4.1 对象::实例方法

public class Student {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public static void test01() {
    Consumer c1 = (x) -> System.out.println(x);
    c1.accept("公众号JAVA前线");

    Consumer c2 = System.out::println;
    c2.accept("公众号JAVA前线");

    Student student = new Student("公众号JAVA前线");
    Supplier s1 = () -> student.getName();
    System.out.println(s1.get());

    Supplier s2 = student::getName;
    System.out.println(s2.get());
}


4.2 类::实例方法

public class Student {
    private int age;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


public static void test02() {
    BiPredicate bp1 = (x, y) -> x.equals(y);
    System.out.println(bp1.test("公众号""JAVA前线"));
    // 类::实例方法
    BiPredicate bp2 = String::equals;
    System.out.println(bp2.test("公众号""JAVA前线"));

    List list = new ArrayList();
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    // 类::实例方法
    Collections.sort(list, Comparator.comparing(Student::getAge));
}

4.3 类::静态方法

public class Student {

    private int age;
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public static int compareAge(Student s1, Student s2) {
        return s1.getAge().compareTo(s2.getAge());
    }
}

public static void test03() {
    List list = new ArrayList();
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Student o1, Student o2) {
            return o1.getAge().compareTo(o2.getAge());
        }
    });
    Collections.sort(list, (o1, o2) -> o1.getAge().compareTo(o2.getAge()));
    Collections.sort(list, Comparator.comparing(Student::getAge));
    // 类::静态方法
    Collections.sort(list, Student::compareAge);
}

4.4 类::new

public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }
}

public static void test04() {
    Function f1 = (str) -> new Student(str);
    System.out.println(f1.apply("公众号JAVA前线"));

    Function f2 = Student::new;
    System.out.println(f2.apply("公众号JAVA前线"));

    Function f3 = (num) -> new Integer[num];
    System.out.println(f3.apply(15));

    Function f4 = Integer[]::new;
    System.out.println(f4.apply(15));

    Supplier> s1 = () -> new ArrayList();
    System.out.println(s1.get());

    Supplier> s2 = ArrayList::new;
    System.out.println(s2.get());
}


5 文章总结

本文我们总结了Lambda表达式,函数式接口,方法引用语法,这些语法相较于传统语法改变不小,一开始并不容易理解,还需要反复实践。下一篇文章我们介绍JAVA8强大的StreamAPI语法请继续关注。


JAVA前线 


互联网技术人思考与分享,欢迎长按关注




推荐阅读
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • importjava.util.ArrayList;publicclassPageIndex{privateintpageSize;每页要显示的行privateintpageNum ... [详细]
author-avatar
沫小兮
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有