- 最常见的 Java 8 面试题及答案
- 面试题1: 列出 Java 8 中引入的新特性?
- 面试题2: 什么是FunctionalInterface ?
- 面试题3: 什么是Optional 类?
- 面试题4: 默认方法是什么?
- 面试题5: Lambda表达式的主要特点是什么?
- 面试题6:旧版本的日期和时间有什么缺点?
- 面试题7: Collection API 和 Stream API 有什么区别?
- 面试题8:如何创建函数式接口?
- 面试题9: 什么是 SAM 接口?
- 面试题10:什么是方法引用?
- 面试题11:解释以下代码含义
- 面试题12:什么是Stream API?为什么我们需要 Stream API?
- 面试题13: Java 8 中的 limit() 方法的目的是什么?
- 面试题14:limit和skip有什么区别?
- 面试题15:你将如何使用 Java 8 日期和时间 API 获取当前日期和时间?
- 面试题16: 在 Java 8 中使用 forEach 编写一个程序来打印 5 个随机数?
- 面试题17:编写一个程序,在 Java 8 中使用 forEach 按排序顺序打印 5 个随机数?
- 面试题18: 编写一个 Java 8 程序来获取list集合中所有数字的总和?
- 面试题19: 编写一个 Java 8 程序对数字集合进行平方,然后过滤掉大于 100 的数字,然后求剩余数字的平均值?
- 面试题20: Stream 的 findFirst() 和 findAny() 有什么区别?
- 面试题21: Iterator 和 Spliterator 有什么区别?
- 面试题22:什么是Consumer 功能接口?
- 面试题23:什么是Supplier功能接口?
- 面试题24: Java 8 中的 Nashorn 是什么?
- 面试题25: Map 和 flatMap 流操作有什么区别?
- 面试题26: Java 8 中的 MetaSpace 是什么?
- 面试题26: 什么是 JJS?
- 面试题27:解释 Java 8 中的 StringJoiner 类?我们如何使用 StringJoiner 类实现连接多个字符串?
- 面试题28:编写一个 Java 8 程序来删除集合中的重复元素?
- 面试题29: 编写一个 Java 8 程序来连接两个 Stream?
- 面试题30: 编写一个 Java 8 程序来查找长度大于 5 的列表中的字符串数?
- 总结
在本篇文章中,我们提供了最重要最常见的 Java 8 面试问题及其答案整理,当前还包含代码示例和说明:
本文中列出的所有重要问题都特定于 Java 8。随着新版本的推出,Java 已经(随着时间的推移)发生了很大的变化。对于每个版本,都会有一些新增功能,而现在企业中比较主流的仍然是Java8。本文将介绍相关重要的面试知识点。
这些是非常常见的问题,在任何需要高级技能的 Java 面试中都会问到这些问题。也是一些大厂非常喜欢问的问题。本文将非常适合 Java 开发人员以及 Java 测试人员/自动化测试人员或任何在同一领域追求更高薪水的人。
最常见的 Java 8 面试题及答案
面试题1: 列出 Java 8 中引入的新特性?
答: Java 8 中引入的新特性如下:
- Lambda 表达式:Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
- 方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少默认方法: 默认方法就是一个在接口里面有了一个实现的方法。
- 新工具:新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。
- Optional 类: Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
- Nashorn, JavaScript 引擎: Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。
- Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
- Date Time API: 加强对日期与时间的处理。
面试题2: 什么是FunctionalInterface ?
答:FunctionalInterface也称为“函数式接口”, 是只有一个抽象方法的接口。这些接口的实现是使用 Lambda 表达式提供的,这意味着要使用 Lambda 表达式,需要创建一个新的函数式接口,或者可以使用Java 8 的预定义函数式接口。
用于创建新FunctionalInterface 的注解是@FunctionalInterface
。
JDK中的函数式接口举例如下:
- java.lang.Runnable,
- java.awt.event.ActionListener,
- java.util.Comparator,
- java.util.concurrent.Callable
- java.util.function包下的接口,如Consumer、Predicate、Supplier等
面试题3: 什么是Optional 类?
答:Optional 类是 Java 8 中引入的一个特殊包装类,用于避免 NullPointerException。这个类存在于 java.util 包下。当我们未能执行 Null 检查时会发生 NullPointerException。
面试题4: 默认方法是什么?
答:简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。
语法:
public interface questions{ default void print() { System.out.println("www.panziye.com"); } }
面试题5: Lambda表达式的主要特点是什么?
- 定义为 Lambda 表达式的方法可以作为参数传递给另一个方法。
- 方法可以独立存在而不属于某个类。
- 无需声明参数类型,因为编译器可以从参数值中获取类型。
- 使用多个参数时可以使用括号,但使用单个参数时不需要括号。
- 如果表达式主体只有一条语句,则无需包含花括号。
面试题6:旧版本的日期和时间有什么缺点?
答: 下面列出的是旧日版本期和时间的缺点:
- java.util.Date 是可变的并且不是线程安全的,而新的 Java 8 日期和时间 API 是线程安全的。
- Java 8 日期和时间 API 符合 ISO 标准,而旧的日期和时间设计不佳。
- 它为日期引入了几个 API 类,如 LocalDate、LocalTime、LocalDateTime 等。
- 谈到两者之间的性能,Java 8 比旧的日期和时间机制运行得更快。
面试题7: Collection API 和 Stream API 有什么区别?
答: Stream API 和 Collection API 的区别可以从下表中理解:
面试题8:如何创建函数式接口?
答:可以用注解@FunctionalInterface
自定义一个函数式接口。一旦定义了功能接口,就只能有一个抽象方法。由于您只有一个抽象方法,因此您可以编写多个静态方法和默认方法。
下面是为两个数字相乘而编写的 FunctionalInterface 的编程示例。
@FunctionalInterface interface FuncInterface { public int multiply(int a, int b); } public class Java8 { public static void main(String args[]) { FuncInterface Total = (a, b) -> a * b; System.out.println("Result: "+Total.multiply(30, 60)); } }
面试题9: 什么是 SAM 接口?
答: Java 8 引入了 FunctionalInterface 的概念,它只能有一个抽象方法。由于这些接口仅指定一种抽象方法,因此有时将它们称为 SAM 接口。SAM 代表“单一抽象方法”。
面试题10:什么是方法引用?
答:在 Java 8 中,引入了一个新特性,称为方法引用。这是用来指函数式接口的方法。在引用方法时,它可以用来替换 Lambda 表达式。
//例如:如果使用 Lambda 表达式: number -> System.out.println(number ) //那么相应的方法引用如下: System.out::println
其中::
是区分类名和方法名的运算符。
面试题11:解释以下代码含义
String:: Valueof表达式
答:是对String类的ValueOf 方法的静态方法引用。System.out::println 是对 System 类的 out 对象的 println 方法的静态方法引用。它返回所传递参数的相应字符串表示形式。参数可以是字符、整数、布尔值等。
面试题12:什么是Stream API?为什么我们需要 Stream API?
答: Stream API 是 Java 8 中添加的新功能。它是一个特殊的类,用于处理来自 Collection 等数据源的对象。
我们需要 Stream API,因为:
- 它支持聚合操作,使处理变得简单。
- 它支持函数式编程。
- 它的处理速度更快。因此,它易于获得更好的性能。
- 它允许并行操作。
面试题13: Java 8 中的 limit() 方法的目的是什么?
答: Stream.limit() 方法指定元素的限制。您在 limit(X) 中指定的大小,它将返回大小为“X”的 Stream。它是 java.util.stream.Stream 的一个方法
面试题14:limit和skip有什么区别?
答: limit() 方法用于返回指定大小的Stream。例如, 如果您提到了 limit(5),那么输出元素的数量将为 5。让我们考虑以下示例。此处的输出返回六个元素,因为限制设置为“6”。
import java.util.stream.Stream; public class Java8 { public static void main(String[] args) { Stream.of(0,1,2,3,4,5,6,7,8) .limit(6) /*limit is set to 6, hence it will print the numbers starting from 0 to 5 */ .forEach(num->System.out.print("\n"+num)); } } //输出0 1 2 3 4 5
而 skip() 方法用于跳过元素。让我们考虑以下示例。在输出中,元素是 6、7、8,这意味着它已经跳过元素直到第 6 个索引(从 1 开始)。
import java.util.stream.Stream; public class Java8 { public static void main(String[] args) { Stream.of(0,1,2,3,4,5,6,7,8) .skip(6) /* It will skip till 6th index. Hence 7th, 8th and 9th index elements will be printed */ .forEach(num->System.out.print("\n"+num)); } } //输出6 7 8
面试题15:你将如何使用 Java 8 日期和时间 API 获取当前日期和时间?
答:下面的程序是借助 Java 8 中引入的新 API 编写的。我们使用了 LocalDate、LocalTime 和 LocalDateTime API 来获取当前日期和时间。
在第一个和第二个打印语句中,我们从系统时钟中检索了当前日期和时间,并将时区设置为默认值。在第三个打印语句中,我们使用了 LocalDateTime API,它将打印日期和时间。
class Java8 { public static void main(String[] args) { System.out.println("Current Local Date: " + java.time.LocalDate.now()); //Used LocalDate API to get the date System.out.println("Current Local Time: " + java.time.LocalTime.now()); //Used LocalTime API to get the time System.out.println("Current Local Date and Time: " + java.time.LocalDateTime.now()); //Used LocalDateTime API to get both date and time } }
面试题16: 在 Java 8 中使用 forEach 编写一个程序来打印 5 个随机数?
答:下面的程序在 Java 8 中借助 forEach 生成 5 个随机数。您可以根据要生成的随机数的数量将限制变量设置为任意数字。
import java.util.Random; class Java8 { public static void main(String[] args) { Random random = new Random(); random.ints().limit(5).forEach(System.out::println); /* limit is set to 5 which means only 5 numbers will be printed with the help of terminal operation forEach */ } }
面试题17:编写一个程序,在 Java 8 中使用 forEach 按排序顺序打印 5 个随机数?
答:下面的程序在 Java 8 中借助 forEach 生成 5 个随机数。您可以根据要生成的随机数的数量将限制变量设置为任意数字。您唯一需要在此处添加的是 sorted() 方法。
import java.util.Random; class Java8 { public static void main(String[] args) { Random random = new Random(); random.ints().limit(5).sorted().forEach(System.out::println); /* sorted() method is used to sort the output after terminal operation forEach */ } }
面试题18: 编写一个 Java 8 程序来获取list集合中所有数字的总和?
答:在这个程序中,我们使用 ArrayList 来存储元素。然后,在 sum() 方法的帮助下,我们计算了 ArrayList 中存在的所有元素的总和。然后将其转换为 Stream 并在 mapToInt() 和 sum() 方法的帮助下添加每个元素。
import java.util.*; class Java8 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(10); list.add(20); list.add(30); list.add(40); list.add(50); // Added the numbers into Arraylist System.out.println(sum(list)); } public static int sum(ArrayList<Integer> list) { return list.stream().mapToInt(i -> i).sum(); // Found the total using sum() method after // converting it into Stream } }
面试题19: 编写一个 Java 8 程序对数字集合进行平方,然后过滤掉大于 100 的数字,然后求剩余数字的平均值?
答:在这个程序中,我们采用了一个整数数组并将它们存储在一个列表中。然后在 mapToInt() 的帮助下,我们对元素进行平方并过滤掉大于 100 的数字。最后,计算剩余数字(大于 100)的平均值。
import java.util.Arrays; import java.util.List; import java.util.OptionalDouble; public class Java8 { public static void main(String[] args) { Integer[] arr = new Integer[] { 100, 100, 9, 8, 200 }; List<Integer> list = Arrays.asList(arr); // Stored the array as list OptionalDouble avg = list.stream().mapToInt(n -> n * n).filter(n -> n > 100).average(); /* Converted it into Stream and filtered out the numbers which are greater than 100. Finally calculated the average */ if (avg.isPresent()) System.out.println(avg.getAsDouble()); } }
面试题20: Stream 的 findFirst() 和 findAny() 有什么区别?
答:顾名思义,findFirst() 方法用于从流中查找第一个元素,而 findAny() 方法用于从流中查找任何元素。findFirst() 本质上是预定论,而 findAny() 是非确定性的。在编程中,确定性意味着输出基于系统的输入或初始状态。
面试题21: Iterator 和 Spliterator 有什么区别?
面试题22:什么是Consumer 功能接口?
答:Consumer 函数接口也是单参数接口(如 Predicate
在下面的程序中,我们使用了 accept 方法来检索 String 对象的值。
import java.util.function.Consumer; public class Java8 { public static void main(String[] args) Consumer<String> str = str1 -> System.out.println(str1); str.accept("Saket"); /* We have used accept() method to get the value of the String Object */ } }
面试题23:什么是Supplier功能接口?
答:Supplier功能接口不接受输入参数。它属于 java.util.function.Supplier。这将使用 get 方法返回值。在下面的程序中,我们使用了 get 方法来检索 String 对象的值。
import java.util.function.Supplier; public class Java8 { public static void main(String[] args) { Supplier<String> str = () -> "Saket"; System.out.println(str.get()); /* We have used get() method to retrieve the value of String object str. */ } }
面试题24: Java 8 中的 Nashorn 是什么?
答: Java 8 中的 Nashorn 是一个基于 Java 的引擎,用于执行和评估 JavaScript 代码。
面试题25: Map 和 flatMap 流操作有什么区别?
答: Map Stream 操作为每个输入值提供一个输出值,而 flatMap Stream 操作为每个输入值提供零个或多个输出值。
面试题26: Java 8 中的 MetaSpace 是什么?
答:在 Java 8 中,引入了一个新特性来存储类。存储在 Java 8 中的所有类的区域称为 MetaSpace。MetaSpace 已取代 PermGen。
在 Java 7 之前,Java 虚拟机使用 PermGen 来存储类。由于 MetaSpace 是动态的,因为它可以动态增长并且没有任何大小限制,Java 8 用 MetaSpace 取代了 PermGen。
面试题26: 什么是 JJS?
答: JJS 是一个命令行工具,用于在控制台执行 JavaScript 代码。在 Java 8 中,JJS 是新的可执行文件,它是一个 JavaScript 引擎。
面试题27:解释 Java 8 中的 StringJoiner 类?我们如何使用 StringJoiner 类实现连接多个字符串?
答:在 Java 8 中,包 java.util 中引入了一个新类,称为 StringJoiner。通过这个类,我们可以连接多个由分隔符分隔的字符串,并为它们提供前缀和后缀。
在下面的程序中,我们将学习如何使用 StringJoiner 类连接多个字符串。在这里,我们将“,”作为两个不同字符串之间的分隔符。然后我们在 add() 方法的帮助下添加了五个不同的字符串。最后,打印 String Joiner。
import java.util.StringJoiner; public class Java8 { public static void main(String[] args) { StringJoiner stj = new StringJoiner(","); // Separated the elements with a comma in between. stj.add("Saket"); stj.add("John"); stj.add("Franklin"); stj.add("Ricky"); stj.add("Trevor"); // Added elements into StringJoiner “stj” System.out.println(stj); } }
面试题28:编写一个 Java 8 程序来删除集合中的重复元素?
答:在这个程序中,我们将元素存储到一个数组中,并将它们转换为一个列表。此后,我们使用了流并在“Collectors.toSet()”方法的帮助下将其收集到“Set”。
import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Java8 { public static void main(String[] args) { Integer[] arr1 = new Integer[] { 1, 9, 8, 7, 7, 8, 9 }; List<Integer> listdup = Arrays.asList(arr1); // Converted the Array of type Integer into List Set<Integer> setNoDups = listdup.stream().collect(Collectors.toSet()); // Converted the List into Stream and collected it to “Set” // Set won't allow any duplicates setNoDups.forEach((i) -> System.out.print(" " + i)); } }
面试题29: 编写一个 Java 8 程序来连接两个 Stream?
答:在这个程序中,我们从两个已经创建的列表中创建了两个 Stream,然后使用 concat() 方法将它们连接起来,其中两个列表作为参数传递。最后,打印连接流的元素。
import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Java8 { public static void main(String[] args) { List<String> list1 = Arrays.asList("Java", "8"); List<String> list2 = Arrays.asList("explained", "through", "programs"); Stream<String> concatStream = Stream.concat(list1.stream(), list2.stream()); // Concatenated the list1 and list2 by converting them into Stream concatStream.forEach(str -> System.out.print(str + " ")); // Printed the Concatenated Stream } }
面试题30: 编写一个 Java 8 程序来查找长度大于 5 的列表中的字符串数?
答:在这个程序中,使用 add() 方法将四个字符串添加到列表中,然后借助 Stream 和 Lambda 表达式,我们统计了长度大于 5 的字符串。
import java.util.ArrayList; import java.util.List; public class Java8 { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("Saket"); list.add("Saurav"); list.add("Softwaretestinghelp"); list.add("Steve"); // Added elements into the List long count = list.stream().filter(str -> str.length() > 5).count(); /* Converted the list into Stream and filtering out the Strings whose length more than 5 and counted the length */ System.out.println("We have " + count + " strings with length greater than 5"); } }
总结
以上就是30个最常见的Java8面试题及答案整理,你学会了吗?