Java8新特性——Lambda表达式之基本语法 & 自定义函数式接口

简介: Java8新特性——Lambda表达式之基本语法 & 自定义函数式接口

1.写在前面


目前我们学习Java主要用到的应该就是Java8了,或者说大部分企业当前使用的也是Java8。那么既然Java8的应用如此之广泛,一定有一些亮点所在:

1.    Lambda 表达式

2.    函数式接口

3.    方法引用与构造器引用

4.    Stream API

5.    接口中的默认方法与静态方法

6.    新时间日期API

7.    其他新特性

速度更快、代码更少(增加了新的语法Lambda表达式)、强大的 Stream API、便于并行、最大化减少空指针异常 Optional

2.为什么要使用Lambda表达式?


Lambda是一个匿名函数数,我们可以把 Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java语言表达能力得到了提升。

3.Lambda表达式的基本语法


Lambda表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “  -> ” 该操作符被称为 Lambda 操作符或剪头操作符。

它将 Lambda 分为两个部分:

·       左侧:指定了 Lambda 表达式需要的所有参数。

·       右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。

具体的就看下面的代码案例。

package com.szh.java8;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
 * Lambda 表达式的基础语法:
 *   Java8中引入了一个新的操作符 "->"
 *   该操作符称为 箭头操作符 或 Lambda操作符
 *   箭头操作符将 Lambda 表达式拆分成两部分:
 *
 *   左侧:Lambda 表达式的参数列表
 *   右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 *
 * Lambda 表达式需要“函数式接口”的支持
 *   函数式接口:接口中只有一个抽象方法的接口, 称为函数式接口
 *   可以使用注解 @FunctionalInterface 修饰, 可以检查是否是函数式接口
 */
public class MyTest2 {
    /**
     * 语法格式一:无参数,无返回值
     *   () -> System.out.println("Hello World!!!");
     */
    @Test
    public void test1() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello World!!!");
            }
        };
        r1.run();
        System.out.println("---------------------------");
        Runnable r2 = () -> System.out.println("Hello World!!!");
        r2.run();
    }
}

package com.szh.java8;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
 * Lambda 表达式的基础语法:
 *   Java8中引入了一个新的操作符 "->"
 *   该操作符称为 箭头操作符 或 Lambda操作符
 *   箭头操作符将 Lambda 表达式拆分成两部分:
 *
 *   左侧:Lambda 表达式的参数列表
 *   右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 *
 * Lambda 表达式需要“函数式接口”的支持
 *   函数式接口:接口中只有一个抽象方法的接口, 称为函数式接口
 *   可以使用注解 @FunctionalInterface 修饰, 可以检查是否是函数式接口
 */
public class MyTest2 {
    /**
     * 语法格式二:有一个参数,无返回值
     *   (x) -> System.out.println(x)
     *   此语法格式中小括号可以省略不写,等价于
     *   x -> System.out.println(x)
     */
    @Test
    public void test2() {
        Consumer<String> consumer = (str) -> System.out.println(str);
        consumer.accept("Lambda表达式真好用....");
    }
}

package com.szh.java8;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
 * Lambda 表达式的基础语法:
 *   Java8中引入了一个新的操作符 "->"
 *   该操作符称为 箭头操作符 或 Lambda操作符
 *   箭头操作符将 Lambda 表达式拆分成两部分:
 *
 *   左侧:Lambda 表达式的参数列表
 *   右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 *
 * Lambda 表达式需要“函数式接口”的支持
 *   函数式接口:接口中只有一个抽象方法的接口, 称为函数式接口
 *   可以使用注解 @FunctionalInterface 修饰, 可以检查是否是函数式接口
 */
public class MyTest2 {
    /**
     * 语法格式三:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句
     */
    @Test
    public void test3() {
        Comparator<Integer> comparator = (x,y) -> {
            System.out.println("函数式接口....");
            return Integer.compare(x,y);
        };
    }
}
package com.szh.java8;
import org.junit.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
 * Lambda 表达式的基础语法:
 *   Java8中引入了一个新的操作符 "->"
 *   该操作符称为 箭头操作符 或 Lambda操作符
 *   箭头操作符将 Lambda 表达式拆分成两部分:
 *
 *   左侧:Lambda 表达式的参数列表
 *   右侧:Lambda 表达式中所需执行的功能, 即 Lambda 体
 *
 * Lambda 表达式需要“函数式接口”的支持
 *   函数式接口:接口中只有一个抽象方法的接口, 称为函数式接口
 *   可以使用注解 @FunctionalInterface 修饰, 可以检查是否是函数式接口
 */
public class MyTest2 {
    /**
     * 语法格式四:若 Lambda 体中只有一条语句,
     *           则 return 和 大括号都可以省略不写
     * Lambda 表达式的参数列表的数据类型可以省略不写,
     * 因为JVM编译器通过上下文推断出,数据类型,即 “类型推断”
     */
    @Test
    public void test4() {
        Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
    }
}

上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台
推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的类型推断

4.自定义函数式接口


只包含一个抽象方法的接口,称为口。


你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)

我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。


就像Runnable接口一样,它就是一个典型的函数式接口。

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface {@code Runnable} is used
     * to create a thread, starting the thread causes the object's
     * {@code run} method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method {@code run} is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

那么我们肯定也可以自定义函数式接口了,首先是没有泛型的自定义函数式接口。

package com.szh.java8.two;
/**
 *
 */
@FunctionalInterface
public interface MyFunction {
    public String getValue(String str);
}
package com.szh.java8.two;
/**
 *
 */
public class TestLambda {
    private static String strHandler(String str,MyFunction mf) {
        return mf.getValue(str);
    }
    public static void main(String[] args) {
        //去除首尾空格
        String trimStr = strHandler("\t\t\t  张起灵-小哥   ",(str) -> str.trim());
        System.out.println(trimStr);
        //转为大写
        String upperStr = strHandler("hello world",str -> str.toUpperCase());
        System.out.println(upperStr);
        //部分截取
        String newStr = strHandler("学Java的冷少",(str) -> str.substring(0,5));
        System.out.println(newStr);
    }
}


下面再来看一个带泛型的函数式接口。

package com.szh.java8.three;
/**
 *
 */
@FunctionalInterface
public interface MyFunction2<T,R> {
    public R getValue(T t1,T t2);
}
package com.szh.java8.three;
import com.szh.java8.two.MyFunction;
/**
 *
 */
public class TestLambda {
    private static void operation(Long l1,Long l2,MyFunction2<Long,Long> mf) {
        System.out.println(mf.getValue(l1,l2));
    }
    public static void main(String[] args) {
        //和
        operation(100L,200L,(x,y) -> x + y);
        //积
        operation(300L,500L,(x,y) -> x * y);
    }
}

作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接收 Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。

相关文章
|
9月前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
359 1
|
10月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
283 11
|
10月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
Java API 开发者
389 0
|
11月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
1317 23
|
11月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。
1225 0
|
11月前
|
数据采集 JSON Java
Java爬虫获取1688店铺所有商品接口数据实战指南
本文介绍如何使用Java爬虫技术高效获取1688店铺商品信息,涵盖环境搭建、API调用、签名生成及数据抓取全流程,并附完整代码示例,助力市场分析与选品决策。
|
11月前
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
585 211
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。