Java8新特性之Lambda表达式,函数式接口,方法引用和default关键字

简介: 前言文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820…种一棵树最好的时间是十年前,其次是现在

絮叨


今天 开始写Java8新特性系列,怎么说呢,主要有几个新东西

  • Lambda表达式
  • 函数式接口
  • 方法引用
  • Stream流
  • Optionl类
  • default关键字

这个四个的主要作用 简化代码编写,提高性能等等,但是也会给维护带来麻烦,因为不懂的人去看,真心累,但是写起来是真的香,今天打算讲标题上的。 考虑大家可能对 内部类 和 泛型不熟悉,有需要的可以看我这2篇文章

🔥你不知道的Java内部类

🔥你必须知道的Java泛型

文本力求简单讲清每个知识点,希望大家看完能有所收获


Lambda表达式简介


Lambda 表达式,也可称为闭包,允许把函数作为一个参数,使代码更简洁。

那么什么是函数式编程呢?

首先,什么是函数式编程,引用廖雪峰先生的教程里面的解释就是说:函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用。而允许使用变量的程序设计语言,由于函数内部的变量状态不确定,同样的输入,可能得到不同的输出,因此,这种函数是有副作用的。函数式编程的一个特点就是,允许把函数本身作为参数传入另一个函数,还允许返回一个函数!

基本语法


// 1. 不需要参数,返回值为 5  
() -> 5  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)  
(String s) -> System.out.print(s)
复制代码


这个几个基本语法 和下面的4种函数式接口是对应的。谢谢读者的提醒。本来还没把这块加上去,新手看起来有点懵逼。


基础列子


创建线程


再来看看遍历Map集合:


引入lambda表达式的一个最直观的作用就是大大的简化了代码的开发,像其他一些编程语言Scala,Python等都是支持函数式的写法的。当然,不是所有的接口都可以通过这种方法来调用,只有函数式接口才行,jdk1.8里面定义了好多个函数式接口,我们也可以自己定义一个来调用,下面说一下什么是函数式接口。


函数式接口


  • 只包含一个抽象方法的接口,称为函数式接口。
  • 可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方 法上进行声明)。
  • 可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包 含一条声明,说明这个接口是一个函数式接口。
  • 之所以Lambda必须和函数式接口配合是因为,接口如果多个函数,则Lambda表达式无法确定实现的是哪个

来个简单的例子


这是一个自定义的函数式接口:作用是传入一个参数,返回一个参数。


@FunctionalInterface
public interface MyNumber<T> {
    T getValue(T t);
}
复制代码


这是用法

public static void main(String[] args) {
        //Lambda的写法
        System.out.println(toUpperString(str -> str.toUpperCase(), "abc")); //ABC
        //匿名内部类的写法
        System.out.println(toUpperString(new MyNumber<String>() {
            @Override
            public String getValue(String s) {
                return s;
            }
        }, "abc"));
    }
    public static String toUpperString(MyNumber<String> mn, String str) {
        return mn.getValue(str);
    }
复制代码


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


Java 内置四大核心函数式接口



函数式接口 参数类型 返回类型 用途
Consumer 消费型接口 T void 对类型为T的对象应用操 作,包含方法: void accept(T t)
Supplier 供给型接口 T 返回类型为T的对象,包 含方法:T get();
Function<T, R> 函数型接口 T R 对类型为T的对象应用操 作,并返回结果。结果 是R类型的对象。包含方 法:R apply(T t);
Predicate 断言型接口 T boolean 确定类型为T的对象是否 满足某约束,并返回 boolean 值。包含方法 boolean test(T t);

使用场景


之前MyNumber这种接口配合Lambda使用,可以发现必须先声明接口,很麻烦,而内置的几个接口就是解决这种问题的;而这些内置的接口也存在大量的内部实现,或者编程者自己定义的类,只要符合对应的参数类型和返回值类型的,都可以使用。例如:定义MyClass只要符合参数T返回R,则都可以使用Function<T, R> 函数型接口对应形式,包含下面的构造器引用,方法引用等等形式

如下:


public static void main(String[] args) {
        //Lambda的写法
        System.out.println(toUpperString1(str -> str.toUpperCase(), "abc")); //ABC
        //匿名内部类的写法
        System.out.println(toUpperString1(new MyNumber<String>() {
            @Override
            public String getValue(String s) {
                return s;
            }
        }, "abc"));
        //使用内置的函数式接口的lambda写法
        System.out.println(toUpperString(str->str.toUpperCase(),"abc"));
    }
    //内置的函数接口
    public static String toUpperString(Function<String,String> mn, String str) {
        return mn.apply(str);
    }
    //定义的函数接口
    public static String toUpperString1(MyNumber<String> mn, String str) {
        return mn.getValue(str);
    }
复制代码


方法引用与构造器引用


方法引用

当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! (实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!) 方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。 如下三种主要使用情况:

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

例子

//例如:此时Consumer参数类型和返回值和println方法一致
        //对象::实例方法名
        //为什么这样用,因为 ConSumer这个函数接口就是传入参数,返回为void ,并且printl 方法就是这样的
        /**我们看下面的源码 和那个函数接口一样
         *     public void println(String x) {
         *         synchronized (this) {
         *             print(x);
         *             newLine();
         *         }
         *     }
         */
        PrintStream printStream=System.out;
        Consumer<String> con= printStream::println;
        con.accept("haha");
        /类::静态方法名
    Comparator<Integer> com=Integer::compare;
    Comparator<Integer> com1=(x,y)->Integer.compare(x,y);
复制代码


构造器引用

格式: ClassName::new

与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,与构造器参数 列表要与接口中抽象方法的参数列表一致

Function<Integer,MyClass> fun= n->new MyClass(1);
        Function<Integer,MyClass> fun1=MyClass::new ;
        MyClass apply = fun1.apply(1);
复制代码


如果存在多个构造器,会自动匹配对应参数或者无参的构造器,取决于apply传递的参数。


default关键字


 在java里面,我们通常都是认为接口里面是只能有抽象方法,不能有任何方法的实现的,那么在jdk1.8里面打破了这个规定,引入了新的关键字default,通过使用default修饰方法,可以让我们在接口里面定义具体的方法实现,如下  

public interface NewCharacter {
    public void test1();
    public default void test2(){
        System.out.println("我是新特性1");
    }
}
复制代码


那这么定义一个方法的作用是什么呢?为什么不在接口的实现类里面再去实现方法呢?

其实这么定义一个方法的主要意义是定义一个默认方法,也就是说这个接口的实现类实现了这个接口之后,不用管这个default修饰的方法,也可以直接调用,如下。

public class NewCharacterImpl implements NewCharacter{
    @Override
    public void test1() {
    }
    public static void main(String[] args) {
        NewCharacter nca = new NewCharacterImpl();
        nca.test2();
    }
}
复制代码


所以说这个default方法是所有的实现类都不需要去实现的就可以直接调用,那么比如说jdk的集合List里面增加了一个sort方法,那么如果定义为一个抽象方法,其所有的实现类如arrayList,LinkedList等都需要对其添加实现,那么现在用default定义一个默认的方法之后,其实现类可以直接使用这个方法了,这样不管是开发还是维护项目,都会大大简化代码量。

相关文章
|
1月前
|
Java Go 开发工具
【Java】(9)抽象类、接口、内部的运用与作用分析,枚举类型的使用
抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接 口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类abstract static不能同时修饰一个方法。
205 0
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
141 11
|
3月前
|
存储 缓存 安全
Java集合框架(二):Set接口与哈希表原理
本文深入解析Java中Set集合的工作原理及其实现机制,涵盖HashSet、LinkedHashSet和TreeSet三大实现类。从Set接口的特性出发,对比List理解去重机制,并详解哈希表原理、hashCode与equals方法的作用。进一步剖析HashSet的底层HashMap实现、LinkedHashSet的双向链表维护顺序特性,以及TreeSet基于红黑树的排序功能。文章还包含性能对比、自定义对象去重、集合运算实战和线程安全方案,帮助读者全面掌握Set的应用与选择策略。
260 23
|
3月前
|
存储 安全 Java
Java集合框架(一):List接口及其实现类剖析
本文深入解析Java中List集合的实现原理,涵盖ArrayList的动态数组机制、LinkedList的链表结构、Vector与Stack的线程安全性及其不推荐使用的原因,对比了不同实现的性能与适用场景,帮助开发者根据实际需求选择合适的List实现。
|
存储 算法 Oracle
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
19 Java8概述(Java8概述+lambda表达式+函数式接口+方法引用+Stream+新时间API)
313 125
|
11月前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
12月前
|
安全 Java API
Java中的Lambda表达式与Stream API的高效结合####
探索Java编程中Lambda表达式与Stream API如何携手并进,提升数据处理效率,实现代码简洁性与功能性的双重飞跃。 ####
164 0
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。
|
Java API
Java 8新特性:Lambda表达式与Stream API的深度解析
【7月更文挑战第61天】本文将深入探讨Java 8中的两个重要特性:Lambda表达式和Stream API。我们将首先介绍Lambda表达式的基本概念和语法,然后详细解析Stream API的使用和优势。最后,我们将通过实例代码演示如何结合使用Lambda表达式和Stream API,以提高Java编程的效率和可读性。