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 表达式兼容的函数式接口的类型。

相关文章
|
1天前
|
Java 开发者
Java一分钟之-Lambda表达式与函数式接口
【5月更文挑战第12天】Java 8引入的Lambda表达式简化了函数式编程,与函数式接口结合,实现了代码高效编写。本文介绍了Lambda的基本语法,如参数列表、箭头符号和函数体,并展示了如何使用Lambda实现`Runnable`接口。函数式接口仅有一个抽象方法,可与Lambda搭配使用。`@FunctionalInterface`注解用于确保接口具有单一抽象方法。文章还讨论了常见的问题和易错点,如非函数式接口、类型冲突以及Lambda表达式的局部变量可见性,并提供了避免这些问题的策略。通过理解Lambda和函数式接口,开发者能提高代码可读性和效率。
40 4
|
1天前
|
Java API
Java 8新特性之Lambda表达式与Stream API实践指南
【5月更文挑战第15天】 随着Java语言的不断发展,Java 8作为一个重要的版本,引入了许多令人兴奋的新特性。其中,Lambda表达式和Stream API是Java 8最受关注的两个特性。本文将深入探讨Lambda表达式的基本概念、语法和使用场景,以及如何结合Stream API实现更加简洁、高效的代码编写。通过实例演示,帮助读者快速掌握这两个新特性,提高Java编程能力。
|
1天前
|
Java
Java正则表达式去掉非汉字字符
【5月更文挑战第11天】Java正则表达式去掉非汉字字符
15 3
|
1天前
|
Java API 开发者
Java中Lambda表达式的深入理解与应用
【5月更文挑战第12天】在Java 8之后,Lambda表达式已经成为了Java开发者必备的技能之一。Lambda表达式以其简洁、灵活的特点,大大提高了编程的效率。本文将深入探讨Lambda表达式的基本概念,语法规则,以及在实际开发中的应用,帮助读者更好地理解和使用Lambda表达式。
|
1天前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的深度解析
【5月更文挑战第12天】本文将深入探讨Java 8中的两个重要新特性:Lambda表达式和Stream API。我们将从基本概念入手,逐步深入到实际应用场景,帮助读者更好地理解和掌握这两个新特性,提高Java编程效率。
41 2
|
Java Unix 数据库管理
java定时框架:表达式设置
Quartz中时间表达式的设置-----corn表达式 (注:这是让我看比较明白的一个博文,但是抱歉,没有找到原作者,如有侵犯,请告知)   时间格式: ,   分别对应: 秒>分>小时>日>月>周>年,  举例: 1.
847 0
|
1天前
|
安全 Java 调度
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第12天】 在现代软件开发中,多线程编程是提升应用程序性能和响应能力的关键手段之一。特别是在Java语言中,由于其内置的跨平台线程支持,开发者可以轻松地创建和管理线程。然而,随之而来的并发问题也不容小觑。本文将探讨Java并发编程的核心概念,包括线程安全策略、锁机制以及性能优化技巧。通过实例分析与性能比较,我们旨在为读者提供一套既确保线程安全又兼顾性能的编程指导。
|
1天前
|
安全 Java 开发者
深入理解Java并发编程:线程安全与性能优化
【5月更文挑战第15天】本文将深入探讨Java并发编程的核心概念,包括线程安全和性能优化。我们将通过实例分析,理解线程安全的重要性,并学习如何通过各种技术和策略来实现它。同时,我们也将探讨如何在保证线程安全的同时,提高程序的性能。
|
1天前
|
消息中间件 并行计算 Java
Java中的多线程编程:基础知识与实践
【5月更文挑战第15天】 在现代计算机编程中,多线程是一个复杂但必不可少的概念。特别是在Java这种广泛使用的编程语言中,理解并掌握多线程编程是每个开发者必备的技能。本文将深入探讨Java中的多线程编程,从基础概念到实际应用场景,为读者提供全面的理论支持和实践指导。
|
1天前
|
Java 程序员 调度
Java中的多线程编程:从理论到实践
【5月更文挑战第14天】在现代计算机技术中,多线程编程是一个重要的概念。它允许多个线程并行执行,从而提高程序的运行效率。本文将从理论和实践两个角度深入探讨Java中的多线程编程,包括线程的基本概念、创建和控制线程的方法,以及如何处理线程同步和通信问题。