一、简介

毫无疑问,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.0接口中的默认方法和静态方法

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

  5. c# 匿名函数和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_接口_默认方法&静态方法

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

  9. 【Java8新特性】- 接口中默认方法修饰为普通方法

    Java8新特性 - 接口中默认方法修饰为普通方法 生命不息,写作不止 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学 ...

随机推荐

  1. py3+urllib+re,爬虫下载捧腹网图片

    实现原理及思路请参考我的另外几篇爬虫实践博客 py3+urllib+bs4+反爬,20+行代码教你爬取豆瓣妹子图:http://www.cnblogs.com/UncleYong/p/6892688. ...

  2. 倒置输入的整数(C、Python)

      C语言: # include <stdio.h> void f(int num) { , j=, yu; printf("转置后:"); ) { yu = num ...

  3. Sublime Text3—系统设置

    摘要 软件的设置分为系统设置和快捷键设置两项,这次分享系统设置,Sublime Text3-自带快捷键介绍前面已分享过. 正文 菜单依次选择Preferences | Settings,我们修改设置不 ...

  4. vue.js2.0开发中的几个技巧

    最近用Vue.js开发了几个项目,Vue的双向数据绑定和组件化让我耳目一新,减少了很多底层重复的工作,和基于jQuey的前端开发不起来,基于Vue的开发给我一种酣畅淋漓的感觉. 下面给出我基于Vue. ...

  5. context configure and clock schedule

    每个窗口都有自己的context,这里演示怎么配置context以及如何实现定时器...... #-*- coding:gbk -*- import pyglet platform=pyglet.wi ...

  6. 不跳转修改url(history.pushState)

    有时候我们会想不跳转的情况下修改url 直接上代码吧: history.pushState(null,"","?test=123") 值得注意的是,为了用户安全 ...

  7. js 定义像java一样的map方便取值【转】

    js 定义像java一样的map方便取值.  百度有位大神说"js对象本身就是一种Map结构",这真是一段让人欢天喜地的代码. <script> //定义一个全局map ...

  8. Weblogic常见故障常:JDBC Connection Pools【转】

    WebLogic Server中数据库连接池是一个经常出问题的地方,总结一下出问题的原因和解决办法. 一.数据库连接泄漏 此类问题一般都是由于开发人员没有正确关闭数据库连接造成的.比如使用完Conne ...

  9. C#常用的正则工具类写法

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

  10. Git fetch & pull

    转:https://blog.csdn.net/qq_36113598/article/details/78906882 1.简单概括 先用一张图来理一下git fetch和git pull的概念: ...