jdk8系列一、jdk8 Lamda表达式语法、接口的默认方法和静态方法、supplier用法

时间:2022-09-24 12:27:10

一、简介

毫无疑问,Java 8是Java自Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。

在本文中我们将学习这些新特性,并用实际的例子说明在什么场景下适合使用。

包含Java开发者经常面对的几类问题:

  • 语言
  • 编译器
  • 工具
  • 运行时(JVM)

二、Lambda表达式和函数式接口

  Lambda表达式(也称为闭包)是Java 8中最大和最令人期待的语言改变。它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理:函数式开发者非常熟悉这些概念。

  很多JVM平台上的语言(Groovy、Scala等)从诞生之日就支持Lambda表达式,但是Java开发者没有选择,只能使用匿名内部类代替Lambda表达式。

  Lambda的设计耗费了很多时间和很大的社区力量,最终找到一种折中的实现方案,可以实现简洁而紧凑的语言结构。

1、Lamda表达式语法

首先不看Lambda本身的写法,可以发现,对于i值的访问,在Lambda中已经不需要声明i为final了。

其次,要明白一个重要的道理:Lambda要求实现的接口中只有一个方法,像上面的Runnable接口就只有一个run方法,如果一个接口中有多于一个方法,则不能写成Lambda的形式。

最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块组成,例如:

Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );

在上面这个代码中的参数e的类型是由编译器推理得出的,你也可以显式指定该参数的类型,例如:

Arrays.asList( "a", "b", "d" ).forEach( ( String e ) -> System.out.println( e ) );

2、Lamda表达式语句块

如果Lambda表达式需要更复杂的语句块,则可以使用花括号将该语句块括起来,类似于Java中的函数体,例如:

    public static void main(String[] args) {
String separator = ",";
Arrays.asList("a","b","c").forEach((String e) -> {
System.out.print(e + separator);
System.out.println(e);
});
}

Lambda表达式可以引用类成员和局部变量(会将这些变量隐式得转换成final的),例如下列两个代码块的效果完全相同:

String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
( String e ) -> System.out.print( e + separator ) );

final String separator = ",";
Arrays.asList( "a", "b", "d" ).forEach(
( String e ) -> System.out.print( e + separator ) );

3、处理返回值

Lambda表达式有返回值,返回值的类型也由编译器推理得出。如果Lambda表达式中的语句块只有一行,则可以不用使用return语句,下列两个代码片段效果相同:

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> e1.compareTo( e2 ) );

Arrays.asList( "a", "b", "d" ).sort( ( e1, e2 ) -> {
int result = e1.compareTo( e2 );
return result;
} );

4、函数接口

  Lambda的设计者们为了让现有的功能与Lambda表达式良好兼容,考虑了很多方法,于是产生了函数接口这个概念。函数接口指的是只有一个函数的接口,这样的接口可以隐式转换为Lambda表达式。java.lang.Runnablejava.util.concurrent.Callable是函数式接口的最佳例子。在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的所有相关接口都已经带有这个注解了),举个简单的函数式接口的定义:

@FunctionalInterface
public interface Functional {
void method();
}

不过有一点需要注意,默认方法和静态方法不会破坏函数式接口的定义,因此如下的代码是合法的。

@FunctionalInterface
public interface FunctionalDefaultMethods {
void method(); default void defaultMethod() {
}
}

更多可以参考官方文档

三、接口的默认方法和静态方法

1、允许接口有默认实现

  Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得接口有点类似traits,不过要实现的目标不一样。默认方法使得开发者可以在 不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。

  默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。接口提供的默认方法会被接口的实现类继承或者覆写,例子代码如下:

public interface Animal {

    default String getName(){
return "animal";
}
}
 private static class DefaultableImpl implements Defaulable {
} private static class OverridableImpl implements Defaulable {
    @Override
    public String notRequired() {
        return "Overridden implementation";
    }
}

2、接口静态方法

  Dog接口使用关键字Animal定义了一个默认方法getName()Cat类实现了这个接口,同时默认继承了这个接口中的默认方法;Dog类也实现了这个接口,但覆写了该接口的默认方法,并提供了一个不同的实现。

Java 8带来的另一个有趣的特性是在接口中可以定义静态方法,例子代码如下:

private interface AnimalFactory {
// Interfaces now allow static methods
static Animal create( Supplier<Animal> supplier ) {
return supplier.get();
}
}

下面的代码片段整合了默认方法和静态方法的使用场景:

Animal dog = AnimalFactory.create(Dog::new);
Animal cat = AnimalFactory.create(Cat::new);
System.out.println(dog.getName());
System.out.println(cat.getName());

这段代码的输出结果如下:

dog
animal

  由于JVM上的默认方法的实现在字节码层面提供了支持,因此效率非常高。默认方法允许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()parallelStream()forEach()removeIf()等等。

  尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引起歧义和编译错误。如果你想了解更多细节,可以参考官方文档

四、supplier用法

supplier也是是用来创建对象的,但是不同于传统的创建对象语法:new,看下面代码:

public class TestSupplier {
private int age; TestSupplier(){
System.out.println(age);
}
public static void main(String[] args) {
//创建Supplier容器,声明为TestSupplier类型,此时并不会调用对象的构造方法,即不会创建对象
Supplier<TestSupplier> sup= TestSupplier::new;
System.out.println("--------");
//调用get()方法,此时会调用对象的构造方法,即获得到真正对象
sup.get();
//每次get都会调用构造方法,即获取的对象不同
sup.get();
}
}

jdk8系列一、jdk8 Lamda表达式语法、接口的默认方法和静态方法、supplier用法的更多相关文章

  1. java8-新特性--(接口的默认方法与静态方法)

    Java 8用默认方法与静态方法这两个新概念来扩展接口的声明. public interface Inte{ void method(); default void defaultMethod(){ ...

  2. java8新特性:接口的默认方法与静态方法

    接口中一共可以定义三种方法: 1.抽象方法,也就是需要实现者必须实现的方法,最常见的那种 2.默认方法,不需要实现者实现 3.静态方法,不需要实现者实现 默认方法: 允许在已有的接口中添加新方法,而同 ...

  3. JDK8新增接口的默认方法与静态方法

    JDK8之前,interface中可以定义常量和抽象方法,访问修饰符是public. public interface A { /** a1和a2写法是等价的 */ public static fin ...

  4. JDK8&period;0接口中的默认方法和静态方法

    我们在接口中通常定义的方法是抽象方法,即没有方法体,只有返回值类型和方法名:(public abstract) void Method(); 类在实现接口的时候必须重写抽象方法才可以 jdk8中新加的 ...

  5. c&num; 匿名函数和lamda表达式语法

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  6. JDK8新特性之接口默认方法与静态方法

    接口默认方法与静态方法 有这样一些场景,如果一个接口要添加一个方法,那所有的接口实现类都要去实现,而某些实现类根本就不需要实现这个方法也要写一个空实现,所以接口默认方法就是为了解决这个问题. 接口静态 ...

  7. Java8新特性之四:接口默认方法和静态方法

    在JDK1.8以前,接口(interface)没有提供任何具体的实现,在<JAVA编程思想>中是这样描述的:"interface这个关键字产生了一个完全抽象的类,它根本就没有提供 ...

  8. JAVA&lowbar;接口&lowbar;默认方法&amp&semi;静态方法

    1.小结(注意): 1.接口中无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰 2.接口中,没有构造方法,不能创建对象 3.接口中,没有静态代码块 ...

  9. Java 8 接口中的默认方法与静态方法

    Java 8 接口中的默认方法与静态方法 1. 接口中的默认方法 允许接口中包含具有具体实现的方法,该方法称"默认方法",默认方法使用用 default 关键字修饰. public ...

随机推荐

  1. LVS 三种工作模式原理、以及优缺点比较(转载)

    原文地址:http://9ilinux.com/149.html 一.NAT模式(VS-NAT) 原理:就是把客户端发来的数据包的IP头的目的地址,在负载均衡器上换成其中一台RS的IP地址,并发至此R ...

  2. C&plus;&plus;(MFC)中WebBrowser去除3D边框的方法(实现IDocHostUIHandler接口)控制 WebBrowser 控件的外观和行为

    在 CSDN 上经常看到以下两个问题:1.在 MFC 应用程序中,如果创建了一个 WebBrowser 控件(包括 CHtmlView 在内),如何可以把该控件的三维边框禁止掉?2.在 MFC 应用程 ...

  3. YTU 2620&colon; B 链表操作

    2620: B 链表操作 时间限制: 1 Sec  内存限制: 128 MB 提交: 418  解决: 261 题目描述 (1)编写一个函数createlink,用来建立一个动态链表(链表中的节点个数 ...

  4. 【iOS发展-70】点菜系统案例:使用文本框inputView和inputAccessoryView串联UIPickerView、UIDatePicker和UIToolBar

    (1)效果 (2)先在storyboard中设计界面,然后源码(直接在ViewController中码) #import "ViewController.h" @interface ...

  5. &lbrack;妙味JS基础&rsqb;第四课:JS数据类型、类型转换

    知识点总结 JS数据类型:number数字(NaN).string字符串.boolean布尔值.函数类型.object对象(obj.[].{}.null).undefined未定义 typeof 用来 ...

  6. vim插件ctags的安装与使用

    LINUX系统下看程序或者编程序时,看到一个函数经常需要知道该函数的定义,这时ctags就派上用场了,其安装和使用方法如下: 安装方法: sudo apt-get install ctags (ubu ...

  7. PostgreSQL 空间数据类型point、 line等

    PostgreSQL中提供了空间类型字段 几何类型 几何数据类型表示二维空间的对象.表6-18 显示了PostgreSQL 里面所有的几何类型.最基本的类型是“点”,它是其它数据类型的基础.   6. ...

  8. &lbrack;Spark&rsqb;&lbrack;Python&rsqb;&lbrack;Application&rsqb;非交互式运行Spark Application 的例子

    非交互式运行Spark Application 的例子 $ cat Count.py import sys from pyspark import SparkContext if __name__ = ...

  9. 读取PBOC电子现金指令流

    该指令流仅适用于T=0协议卡片.   终端对IC卡的响应: 60 须要额外的工作等待时间,说明IC卡端数据还未处理好. 61 发送GET RESPONSE命令取应答数据 6C 加上取字节数,命令重发 ...

  10. BZOJ&period;4316&period;小C的独立集&lpar;仙人掌 DP&rpar;

    题目链接 \(Description\) 求一棵仙人掌的最大独立集. \(Solution\) 如果是树,那么 \(f[i][0/1]\) 表示当前点不取/取的最大独立集大小,直接DP即可,即 \(f ...