# Java 8 教程

> 原文： [https://howtodoinjava.com/java-8-tutorial/](https://howtodoinjava.com/java-8-tutorial/)

此 **Java 8 教程**列出了重要的 **Java 8 特性**，并提供了此发行版中引入的示例。 所有特性均具有指向详细教程的链接，例如 lambda 表达式，Java 流，函数式接口和日期时间 API 更改。

**Java SE 8** 是[于 2014 年初发布的](https://blogs.oracle.com/thejavatutorials/jdk-8-is-released)。 在 Java 8 中，最受关注的特性是 lambda 表达式。 它还具有许多其他重要特性，例如默认方法，流 API 和新的日期/时间 API。 让我们通过示例了解 Java 8 中的*这些新特性*。

```java
Table of Contents

1\. Lambda Expression
2\. Functional Interface
3\. Default Methods
4\. Streams
5\. Date/Time API Changes
```

## 1\. Lambda 表达式

Lambda 表达式对于使用 Scala 等其他流行编程语言的我们很多人并不陌生。 在 Java 编程语言中，Lambda 表达式（或函数）只是*匿名函数*，即不带名称且不受标识符限制的函数。 它们准确地写在需要的地方，通常以*作为其他函数*的参数。

Lambda 表达式的基本*语法为：*

```java
either
(parameters) -> expression
or
(parameters) -> { statements; }
or 
() -> expression

```

典型的 lambda 表达式示例如下所示：

```java
(x, y) -> x + y  //This function takes two parameters and return their sum.

```

请注意，根据`x`和`y`的类型，方法可能会在多个地方使用。 参数可以匹配`int`或`Integer`或简单地也可以匹配`String`。 根据上下文，它将添加两个整数或连接两个字符串。

#### 编写 Lambda 表达式的规则

1.  Lambda 表达式可以具有零个，一个或多个参数。
2.  参数的类型可以显式声明，也可以从上下文中推断出来。
3.  多个参数用强制括号括起来，并用逗号分隔。 空括号用于表示空参数集。
4.  当有单个参数时，如果推断出其类型，则不强制使用括号。 例如`a -> a * a`。
5.  Lambda 表达式的主体可以包含零个，一个或多个语句。
6.  如果 lambda 表达式的主体具有单个语句，则不必使用大括号，并且匿名函数的返回类型与主体表达式的返回类型相同。 如果正文中的语句多于一个，则这些语句必须用大括号括起来。

> 阅读更多： [Java 8 Lambda 表达式教程](//howtodoinjava.com/java8/complete-lambda-expressions-tutorial-in-java/)

## 2\. 函数式接口

函数式接口也称为*单一抽象方法接口（SAM 接口）*。 顾名思义，它们**允许其中恰好是一种抽象方法**。 Java 8 引入了一个注解，即`@FunctionalInterface`，当您注解的接口违反函数式接口的约定时，该注解可用于编译器级错误。

典型的函数式接口示例：

```java
@FunctionalInterface
public interface MyFirstFunctionalInterface {
	public void firstWork();
}

```

请注意，即使省略`@FunctionalInterface`注释，函数式接口也有效。 它仅用于通知编译器在接口内部强制执行单个抽象方法。

另外，由于默认方法不是抽象的，因此*可以随意向函数式接口添加任意数量的默认方法*。

要记住的另一个重要点是，如果接口声明了一个覆盖`java.lang.Object`的公共方法之一的抽象方法，那么该接口的任何实现都将具有`java.lang.Object`的实现，因此这也不会计入接口的抽象方法数量。 例如，下面是完全有效的函数式接口。

```java
@FunctionalInterface
public interface MyFirstFunctionalInterface 
{
	public void firstWork();

	@Override
	public String toString();                //Overridden from Object class

	@Override
	public boolean equals(Object obj);        //Overridden from Object class
}

```

> 阅读更多： [Java 8 函数式接口教程](//howtodoinjava.com/java8/functional-interface-tutorial/)

## 3\. 默认方法

Java 8 允许您在接口中添加非抽象方法。 这些方法必须声明为默认方法。 Java 8 中引入了默认方法以启用 lambda 表达式的特性。

默认方法使您可以向库的接口添加新特性，并确保与为这些接口的较早版本编写的代码二进制兼容。

让我们看一个例子：

```java
public interface Moveable {
    default void move(){
        System.out.println("I am moving");
    }
}

```

`Moveable`接口定义了一种方法`move()`，并提供了默认实现。 如果有任何类实现了此接口，则无需实现其自己的`move()`方法版本。 它可以直接调用`instance.move()`。 例如：

```java
public class Animal implements Moveable{
    public static void main(String[] args){
        Animal tiger = new Animal();
        tiger.move();
    }
}

Output: I am moving

```

如果类愿意自定义`move()`方法的行为，则它可以提供自己的自定义实现并覆盖该方法。

> 重做更多： [Java 8 默认方法教程](//howtodoinjava.com/java8/default-methods-in-java-8/)

## 4\. Java 8 流

引入的另一项重大更改是 **Java 8 流 API** ，它提供了一种以各种方式处理一组数据的机制，这些方式可以包括过滤，转换或任何其他可能对应用程序有用的方式。

Java 8 中的 流 API 支持不同类型的迭代，您可以在其中简单地定义要处理的项目集，对每个项目执行的操作，以及存储这些操作的输出。

流 API 的示例。 在此示例中，`items`是`String`值的集合，您想删除以某些前缀文本开头的条目。

```java
List<String> items;
String prefix;
List<String> filteredList = items.stream().filter(e -> (!e.startsWith(prefix))).collect(Collectors.toList());

```

这里`items.stream()`表示我们希望使用 流 API 处理`items`集合中的数据。

> 阅读更多： [Java 8 内部和外部迭代](//howtodoinjava.com/java8/java-8-tutorial-internal-vs-external-iteration/)

## 5\. Java 8 日期/时间 API 更改

新的日期和时间 API /类（JSR-310），也称为 *ThreeTen* ，它们仅改变了您在 Java 应用程序中处理日期的方式。

#### 日期

`Date`类甚至已过时。 打算替换`Date`类的新类是`LocalDate`，`LocalTime`和`LocalDateTime`。

1.  `LocalDate`类表示日期。 没有时间或时区的表示。
2.  `LocalTime`类表示时间。 没有日期或时区的表示。
3.  `LocalDateTime`类表示日期时间。 没有时区的表示。

如果您想将日期特性与区域信息一起使用，则 Lambda 会为您提供额外的 3 类，类似于上面的一种，即`OffsetDate`，`OffsetTime`和`OffsetDateTime`。 时区偏移可以以“`+05:30`”或“`Europe/Paris`”格式表示。 这是通过使用另一个类即`ZoneId`完成的。

```java
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.of(12, 20);
LocalDateTime localDateTime = LocalDateTime.now(); 
OffsetDateTime offsetDateTime = OffsetDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));

```

#### 时间戳和持续时间

为了随时表示特定的时间戳，需要使用的类是`Instant`。 `Instant`类表示精确到纳秒的时间瞬间。 即时操作包括与另一个`Instant`进行比较，以及增加或减少持续时间。

```java
Instant instant = Instant.now();
Instant instant1 = instant.plus(Duration.ofMillis(5000));
Instant instant2 = instant.minus(Duration.ofMillis(5000));
Instant instant3 = instant.minusSeconds(10);

```

`Duration`类是用 Java 语言首次带来的全新概念。 它表示两个时间戳之间的差异。

```java
Duration duration = Duration.ofMillis(5000);
duration = Duration.ofSeconds(60);
duration = Duration.ofMinutes(10);

```

`Duration`处理较小的时间单位，例如毫秒，秒，分钟和小时。 它们更适合与应用程序代码进行交互。 要与人互动，您需要使**持续时间更长**，该类与`Period`类一起提供。

```java
Period period = Period.ofDays(6);
period = Period.ofMonths(6);
period = Period.between(LocalDate.now(), LocalDate.now().plusDays(60));

```

> 阅读更多： [Java 8 日期和时间 API 更改](//howtodoinjava.com/java8/date-and-time-api-changes-in-java-8-lambda/)

在注释部分中，将您对此 **Java 8 教程**的问题留给我。

学习愉快！