Java SE 8面试题与答案详解(上篇)

这是文章《Java SE 8面试问题和答案(部分一)》的第1部分(共3部分)。

在这篇文章中,我们将讨论一些与Java SE 8面试相关的重要问题和答案。我将写另一篇文章来讨论其他的Java SE 8面试问题。

Java 8 面试问题

  1. 我们为什么需要再次转向Java?
  2. Java SE 8的新特性是什么?
  3. Java SE 8的新特性有什么优点?
  4. Lambda表达式是什么?
  5. Lambda表达式由哪三个部分组成?Lambda表达式的类型是什么?
  6. 函数接口是什么?SAM接口是什么?
  7. 我们可以定义自己的函数接口吗?@FunctionalInterface是什么?定义函数接口的规则是什么?
  8. 定义函数接口是否需要使用@FunctionalInterface注解?@FunctionalInterface注解的作用是什么?为什么我们需要Java中的函数接口?
  9. 什么时候使用Java 8的流API?为什么我们需要在项目中使用Java 8的流API?
  10. 解释集合API和流API之间的区别?
  11. Java SE 8中的Spliterator是什么?Iterator和Spliterator在Java SE 8中有什么区别?
  12. Java 8中Optional是什么?Optional的用途是什么?Java 8 Optional的优点是什么?
  13. 什么是类型推断?类型推断在旧版本(如Java 7及更早版本)中是否可用,还是仅在Java SE 8中可用?

Java 8面试问题和答案

在这个部分,我们将从之前的部分中选择每个问题,并通过详细的描述来回答。如果您需要更多的信息和示例,请查阅《JournalDEV》上提供的之前的Java SE 8帖子。

我们为什么需要再次转换为Java呢?

Oracle公司在Java SE 8中引入了许多新概念,旨在带来以下的好处:

  • 高效利用当前多核CPU
    最近,我们可以观察到硬件方面的巨大变化。如今,所有系统都使用多核CPU(2核、4核、8核、16核等)来部署和运行它们的应用程序。我们需要在Java中使用新的编程结构来高效利用这些多核处理器,以开发高并发和高可扩展性的应用程序。
  • 利用函数式编程特性
    Oracle Corporation在Java SE 8中引入了许多函数式编程(FP)概念,以利用函数式编程的优势。

Java SE 8的新特性是什么?

  • Lambda表达式(Lambda Expressions)
  • 函数式接口(Functional Interfaces)
  • 流API(Stream API)
  • 日期和时间API(Date and Time API)
  • 接口默认方法和静态方法(Interface Default Methods and Static Methods)
  • 分割迭代器(Spliterator)
  • 方法和构造器引用(Method and Constructor References)
  • 集合API增强(Collections API Enhancements)
  • 并发工具增强(Concurrency Utils Enhancements)
  • Fork/Join框架增强(Fork/Join Framework Enhancements)
  • 内部迭代(Internal Iteration)
  • 并行数组和并行集合操作(Parallel Array and Parallel Collection Operations)
  • Optional类
  • 类型注解和可重复注解(Type Annotations and Repeatable Annotations)
  • 方法参数反射(Method Parameter Reflection)
  • Base64编码和解码(Base64 Encoding and Decoding)
  • IO和NIO2增强(IO and NIO2 Enhancements)
  • Nashorn JavaScript引擎
  • javac增强
  • JVM变更
  • Java 8精简配置文件:compact1、compact2、compact3
  • JDBC 4.2
  • JAXP 1.6
  • Java DB 10.10
  • 网络(Networking)
  • 安全变更(Security Changes)

Java SE 8新功能的好处是什么?

从Java SE 8新特性中,我们可以获得以下好处:

  • 更简洁和可读的代码
  • 更可重用的代码
  • 更可测试和可维护的代码
  • 高并发和高可扩展性的代码
  • 编写并行代码的能力
  • 编写类似数据库操作的能力
  • 性能更好的应用程序
  • 更高生产力的代码

Lambda表达式是什么?

Lambda表达式是一种匿名函数,它接受一组输入参数并返回结果。Lambda表达式是一段没有任何名称的代码块,可以有或没有参数,可以有或没有结果。这段代码在需要时执行。

Lambda表达式有哪三个部分?Lambda表达式的类型是什么?

一个Lambda表达式包含3个部分。

  • 参数列表(Parameter List)
    Lambda表达式可以包含零个、一个或多个参数。这是可选的。
  • Lambda箭头运算符(Lambda Arrow Operator)
    “->” 被称为Lambda箭头运算符。它分隔参数列表和函数体。
  • Lambda表达式体(Lambda Expression Body)
    它包含Lambda表达式的执行语句和逻辑。

“Journal Dev” 的类型是 java.lang.String。”true” 的类型是 Boolean。同样地,一个 Lambda 表达式的类型是函数式接口。例如:下述 Lambda 表达式的类型是什么?

   () -> System.out.println("Hello World");

这个Lambda表达式没有参数,并且不返回任何结果。因此它的类型是”java.lang.Runnable”函数式接口。

什么是函数式接口?什么是SAM(单一抽象方法)接口?

一个功能接口是一个只包含一个抽象方法的接口。功能接口也被称为SAM接口,因为它只包含一个抽象方法。SAM接口代表单一抽象方法接口。Java SE 8 API定义了许多功能接口。

我们是否可以定义自己的函数式接口?@FunctionalInterface是什么?定义函数式接口的规则是什么?

是的,我们可以定义自己的函数式接口。@FunctionalInterface是Java SE 8中引入的一个注解,用于指示接口是函数式接口。定义函数式接口的规则包括:

  • 接口只能有一个抽象方法
  • 可以有多个默认方法和静态方法
  • 可以重写Object类中的方法

这是文章《Java SE 8面试问题和答案(部分一)》的第2部分(共3部分)。

是的,我们可以定义自己的函数式接口。我们使用Java SE 8的@FunctionalInterface注解来标记一个接口作为函数式接口。我们需要遵循以下规则来定义一个函数式接口:

  • 定义一个只有一个抽象方法的接口。
  • 我们不能定义多个抽象方法。
  • 在接口定义中使用@FunctionalInterface注解。
  • 我们可以定义任意数量的其他方法,如默认方法、静态方法。
  • 如果我们将java.lang.Object类的方法重写为抽象方法,这不计为抽象方法。

在Java中,是否需要使用@FunctionalInterface注解来定义函数式接口?@FunctionalInterface注解的作用是什么?为什么我们需要函数式接口?

在Java中不是强制使用@FunctionalInterface注解来定义函数式接口。如果不想使用,我们可以省略这个注解。然而,如果在函数式接口定义中使用了它,Java编译器会强制在该接口中只使用一个抽象方法。为什么我们需要函数式接口?在Java SE 8中,Lambda表达式的类型是函数式接口。无论我们在哪里使用Lambda表达式,就意味着我们正在使用函数式接口。

我们什么时候开始使用Java 8 Stream API?为什么我们需要在我们的项目中使用Java 8 Stream API?

当我们的Java项目需要执行以下操作时,最好使用Java 8 Stream API来获得许多好处。

  • 当我们想要执行类似数据库的操作时。例如,我们想要执行分组操作、排序操作等。
  • 当我们想要延迟执行操作时。
  • 当我们想要编写函数式风格的编程时。
  • 当我们想要执行并行操作时。
  • 当我们想要使用内部迭代时。
  • 当我们想要执行管道操作时。
  • 当我们想要获得更好的性能时。

解释 Collection API 和 Stream API 之间的区别是什么?

序号 Collection API Stream API
1. 自Java 1.2版本起可用 在Java SE 8中引入
2. 用于存储数据(一组对象)。 用于计算数据(对一组对象进行计算)。
3. 我们可以使用Spliterator和Iterator来迭代元素。我们可以使用forEach为此流中的每个元素执行一个操作。 我们不能使用Spliterator或Iterator来迭代元素。
4. 用于存储无限数量的元素。 Stream API用于处理集合中的元素。
5. 通常,它使用外部迭代概念来迭代元素,如Iterator。 Stream API使用内部迭代来迭代元素,使用forEach方法。
6. 集合对象是急切构造的。 流对象是延迟构造的。
7. 我们只有在集合对象完全计算后才能向其添加元素。 我们可以在没有任何预先计算的情况下向流对象添加元素。这意味着流对象是按需计算的。
8. 我们可以任意次数地迭代和消耗集合对象中的元素。 我们只能迭代和消耗流对象中的元素一次。

在Java SE 8中,Spliterator是什么?迭代器和Spliterator在Java SE 8中的区别是什么?

Spliterator代表可分割迭代器。这是由Oracle Corporation作为Java SE 8的一部分新引入的。与Iterator和ListIterator一样,它也是Iterator接口中的一种。

序号 Spliterator Iterator
1. 在Java SE 8中引入。 自Java 1.2版本起可用。
2. 可分割迭代器 不可分割迭代器
3. 用于Stream API。 用于Collection API。
4. 它使用内部迭代概念来迭代流。 它使用外部迭代概念来迭代集合。
5. 我们可以使用Spliterator以并行和顺序方式迭代流。 我们只能使用Iterator以顺序方式迭代集合。
6. 我们可以通过在流对象上调用spliterator()方法获取Spliterator。 我们可以通过在集合对象上调用iterator()方法获取Iterator。
7. 重要方法:tryAdvance() 重要方法:next(), hasNext()

在Java 8中,Optional是什么?Optional的用途是什么?Java 8 Optional的优势是什么?

Optional(可选):Optional是Java SE 8中引入的一个最终类,它定义在java.util包中。它用于表示可选存在或不存在的值。它可以包含一个值或者零个值。如果它包含一个值,我们可以获取它。否则,我们获取到的是空值。它是一个有界的集合,即它最多只能包含一个元素。它是”null”值的一个替代品。Optional的主要优势是:

  • 用于避免空值检查。
  • 用于避免”NullPointerException”。

什么是类型推断?类型推断在旧版本的Java 7及之前版本中可用吗?还是仅在Java SE 8中可用?

这是文章《Java SE 8面试问题和答案(部分一)》的第3部分(共3部分)。

类型推断是指在编译时由编译器确定类型。这在Java SE 8中并不是一个新功能,在Java 7中以及Java 7之前也可用。在Java 7之前,让我们来探索Java数组。定义一个包含如下所示值的字符串数组:

String str[] = { "Java 7", "Java 8", "Java 9" };

在这里,我们在右侧分配了一些字符串值,但没有定义其类型。Java编译器会自动推断其类型并创建一个字符串数组。Java 7:Oracle公司在Java SE 7中引入了”钻石操作符”新功能,以避免在泛型中进行不必要的类型定义。

Map<String,List<Customer>> customerInfoByCity = new HashMap<>();

在这里,我们没有在右侧定义类型信息,只是定义了Java SE 7的钻石运算符。在Java SE 8中,Oracle公司在类型推断的概念方面进行了许多改进。我们使用这个概念来定义Lambda表达式、函数、方法引用等。

ToIntBiFunction<Integer,Integer> add = (a,b) -> a + b;

这里,Java编译器在左侧观察到类型定义,并将Lambda表达式参数a和b的类型确定为整数。这就是关于Java 8面试问题的全部内容。我在这篇文章中讨论了一些Java SE 8面试问题,并将在我的下篇文章中继续讨论一些Java SE 8面试问题。如果您喜欢我的文章或有任何问题/建议,请给我留言。

bannerAds