Skip to content

Java8新特性

  • 接口中默认方法与静态方法
  • 函数式接口(Functional Interface)
  • Lambda表达式(Lambda Expressions)
  • 流API(Streams API)
  • Optional 类
  • 新的日期时间API(New Date-Time API)

1、接口中默认方法与静态方法

在Java 8之前,接口只能有方法声明,而不能有方法实现。这意味着一旦接口被更改(比如添加新方法),所有实现了该接口的类都必须随之修改以实现新添加的方法。

Java 8引入的defaultstatic方法正是为了解决这个问题。

default 方法

  • 作用: default方法允许我们在接口中添加有具体实现的非抽象方法。这意味着实现接口的类可以不用实现这些default方法。

  • 用途: 这对于向现有接口添加新功能非常有用,因为它不会破坏实现该接口的现有类的功能。

  • 类比: 想象一下,有一个标准的建筑蓝图(接口)。突然,需要在所有这样的建筑中添加一个新的功能(比如中央供暖)。default方法就像是一个标准的中央供暖系统设计,可以直接加入到现有的蓝图中,而不需要重新设计整个建筑。

static 方法

  • 作用: static方法允许我们在接口中添加静态方法。这些方法可以直接通过接口来调用,而不需要一个接口的实例。

  • 用途: static方法通常用于提供一些与接口相关的工具方法。

  • 类比: 如果接口是一种服务的标准(比如邮寄服务),那么static方法就像是可以直接从服务标准本身获得的额外帮助或工具,如一个在线邮资计算器。

具体使用示例

interface MyInterface {
    // 一个默认方法
    default void newMethod() {
        System.out.println("This is a default method");
    }

    // 一个静态方法
    static void anotherNewMethod() {
        System.out.println("This is a static method");
    }
}

// 实现接口的类
class MyClass implements MyInterface {
    // 不需要实现newMethod()
}

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.newMethod(); // 调用默认方法

        MyInterface.anotherNewMethod(); // 直接调用接口的静态方法
    }
}

在这个例子中,MyClass实现了MyInterface但没有实现newMethod()方法,因为它是一个默认方法。

同时,可以直接通过MyInterface调用静态方法anotherNewMethod()


有一种情况需要重写 default 的接口方法,注意一下,示例如下:

public interface InterfaceNew {
    static void sm() {
        System.out.println("interface提供的方式实现");
    }
    static void sm2() {
        System.out.println("interface提供的方式实现");
    }

    default void def() {
        System.out.println("interface default方法");
    }
    default void def2() {
        System.out.println("interface default2方法");
    }
    //须要实现类重写
    void f();
}

public interface InterfaceNew1 {
    default void def() {
        System.out.println("InterfaceNew1 default方法");
    }
}

如果有一个类既实现了 InterfaceNew 接口又实现了 InterfaceNew1接口,它们都有def(),并且 InterfaceNew 接口和 InterfaceNew1接口没有继承关系的话,这时就必须重写def()

不然的话,编译的时候就会报错。

public class InterfaceNewImpl implements InterfaceNew , InterfaceNew1{
    public static void main(String[] args) {
        InterfaceNewImpl interfaceNew = new InterfaceNewImpl();
        interfaceNew.def();
    }

    @Override
    public void def() {
        InterfaceNew1.super.def();
    }

    @Override
    public void f() {
    }
}

Java8中,接口和抽象类的区别

  • interface 和 class 的区别,主要有:
    • 接口多实现,类单继承
    • 接口的方法是 public abstract 修饰,变量是 public static final 修饰。 abstract class 可以用其他修饰符
  • interface 的方法是更像是一个扩展插件。而 abstract class 的方法是要继承的。

interface 新增defaultstatic修饰的方法,为了解决接口的修改与现有的实现不兼容的问题,并不是为了要替代abstract class

2、函数式接口(Functional Interface)

函数式接口(Functional Interface)是Java 8引入的一个重要概念,它是Java对函数式编程支持的一部分。

定义

函数式接口是只有一个抽象方法的接口。尽管接口可以包含多个默认方法、静态方法,但只能有一个抽象方法。这种接口的主要目的是为了与Lambda表达式结合使用。

@FunctionalInterface 注解

虽然不是强制性的,但通常会使用@FunctionalInterface注解来标记函数式接口。这个注解有助于编译器识别意图,并在接口不是有效的函数式接口时生成编译时错误。

函数式接口示例:

@FunctionalInterface
interface Greeting {
    String sayHello(String name);
}

这个Greeting接口定义了一个接受一个字符串参数并返回一个字符串的方法。

由于它只有一个抽象方法,所以它是一个函数式接口。

使用场景

函数式接口在Java 8中引入Lambda表达式时变得非常重要。Lambda表达式提供了一种简洁的方式来实现函数式接口,从而使代码更简洁、更易读。

可以将函数式接口想象成一种特殊的工具套件。这个套件里只有一个工具槽(抽象方法),但你可以以多种方式(Lambda表达式、方法引用)填充这个槽。这就像是一个可定制的工具,你可以根据需要插入不同的功能。

函数式接口在Java中的很多地方都有使用,例如:

  • java.util.function包中,Java 8引入了一系列标准的函数式接口,如Predicate<T>Function<T,R>Consumer<T>等。
  • 在集合框架中,它们被用于简化迭代、过滤和转换操作。
  • 在并发编程中,例如使用RunnableCallable接口。

3、Lambda 表达式

Lambda表达式是Java 8中一个非常重要的新特性,它为Java带来了一种简洁的方式来表示函数式接口的实例。

Lambda表达式主要用于提供一种简洁、表达式风格的方法来表示可以传递的匿名函数。这种表达方式非常适合创建简短的、只使用一次的方法版本。

语法格式

语法格式

(parameters) -> expression 或
(parameters) ->{ statements; }
  • parameters
    • 与方法定义中的参数列表类似。对于单个参数,可以省略括号
  • ->
    • Lambda表达式的核心,用于分隔参数列表和Lambda体
  • Lambda体
    • 可以是一个表达式或一个代码块。表达式体会返回一个值,而代码块可以包含零个或多个语句。

简易示例

使用示例

Lambda表达式通常与函数式接口一起使用。函数式接口是只有一个抽象方法的接口,这意味着Lambda表达式可以为该抽象方法提供实现。

假设我们有一个简单的函数式接口:

@FunctionalInterface
interface StringOperation {
    int getLength(String s);
}

不使用Lambda表达式,我们可能需要这样实现:

StringOperation operation = new StringOperation() {
    @Override
    public int getLength(String s) {
        return s.length();
    }
};

使用Lambda表达式,我们可以这样简化:

StringOperation operation = s -> s.length();

替代匿名内部类

平时开发经常会用到 Runnable 接口、Comparator 接口、Listener 接口 这三个接口,下面分别就看一下他们的使用示例。

Runnable 接口

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("The runable now is using!");
            }
}).start();
//用lambda
new Thread(() -> System.out.println("It's a lambda function!")).start();

Comparator 接口

List<Integer> strings = Arrays.asList(1, 2, 3);

Collections.sort(strings, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
    return o1 - o2;}
});

//Lambda
Collections.sort(strings, (Integer o1, Integer o2) -> o1 - o2);
//分解开
Comparator<Integer> comparator = (Integer o1, Integer o2) -> o1 - o2;
Collections.sort(strings, comparator);

Listener 接口

JButton button = new JButton();
button.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
   e.getItem();
}
});
//lambda
button.addItemListener(e -> e.getItem());

集合上使用

在集合上的应用

Lambda表达式特别适合用在集合的操作上,比如forEachmapfilter等方法:

List<String> list = Arrays.asList("Java", "Python", "C++");

// 使用Lambda表达式迭代
list.forEach(element -> System.out.println(element));

// 使用Lambda表达式和Stream API进行过滤
list.stream()
    .filter(s -> s.startsWith("J"))
    .forEach(System.out::println);
void lamndaFor() {
        List<String> strings = Arrays.asList("1", "2", "3");
        //传统foreach
        for (String s : strings) {
            System.out.println(s);
        }
        //Lambda foreach
        strings.forEach((s) -> System.out.println(s));
        //or
        strings.forEach(System.out::println);
 				//map
        Map<Integer, String> map = new HashMap<>();
        map.forEach((k,v)->System.out.println(v));
}

方法的引用

Java 8 允许使用 :: 关键字来传递方法或者构造函数引用,无论如何,表达式返回的类型必须是 functional-interface。

public class LambdaClassSuper {
    LambdaInterface sf(){
        return null;
    }
}

public class LambdaClass extends LambdaClassSuper {
    public static LambdaInterface staticF() {
        return null;
    }

    public LambdaInterface f() {
        return null;
    }

    void show() {
        //1.调用静态函数,返回类型必须是functional-interface
        LambdaInterface t = LambdaClass::staticF;

        //2.实例方法调用
        LambdaClass lambdaClass = new LambdaClass();
        LambdaInterface lambdaInterface = lambdaClass::f;

        //3.超类上的方法调用
        LambdaInterface superf = super::sf;

        //4. 构造方法调用
        LambdaInterface tt = LambdaClassSuper::new;
    }
}

访问变量

int i = 0;
Collections.sort(strings, (Integer o1, Integer o2) -> o1 - i);
//i =3;

lambda 表达式可以引用外边变量,但是该变量默认拥有 final 属性,不能被修改,如果修改,编译时就报错。

to be contined......

4、Stream

Stream 是什么

java 新增了 java.util.stream 包,它和之前的流大同小异。之前接触最多的是资源流,比如java.io.FileInputStream,通过流把文件从一个地方输入到另一个地方,它只是内容搬运工,对文件内容不做任何 CRUD。

Stream依然不存储数据,不同的是它可以检索(Retrieve)和逻辑处理集合数据、包括筛选、排序、统计、计数等。可以想象成是 Sql 语句。

它的源数据可以是 CollectionArray 等。由于它的方法参数都是函数式接口类型,所以一般和 Lambda 配合使用。

流类型

  1. stream 串行流
  2. parallelStream 并行流,可多线程执行

Stream 常用方法

  • stream(), parallelStream()
  • filter()
  • findAny() findFirst()
  • sort
  • forEach void
  • map(), reduce()
  • flatMap() - 将多个Stream连接成一个Stream
  • collect(Collectors.toList())
  • distinct, limit
  • count
  • min, max, summaryStatistics

5、Optional

参考: https://javaguide.cn/java/new-features/java8-common-new-features.html#optional

Optional是Java 8引入的一个容器类,用于表示一个值可能存在或不存在。它提供了一种更优雅的方法来处理可空值,从而减少NullPointerException的风险。

to be contined...

6、Date-Time API

to be contined....


参考