Java 8 面试问题(Java 8 Interview Questions)

优质
小牛编辑
133浏览
2023-12-01

亲爱的读者,这些Java 8 Interview Questions专门设计用于让您熟悉在面试Java 8 Language时可能遇到的问题的本质。 根据我的经验,很好的面试官在你的面试中几乎不打算问任何特定的问题,通常问题从这个主题的一些基本概念开始,然后他们继续基于进一步的讨论和你回答的问题 -

Java 8中添加了许多功能,最重要的功能如下所述 -

  • Lambda expression - 为Java添加功能处理功能。

  • Method references - 通过名称引用函数而不是直接调用它们。 使用函数作为参数。

  • Default method - 具有默认方法实现的接口。

  • New tools - 添加了新的编译工具和实用程序,如'jdeps',以确定依赖关系。

  • Stream API - 用于促进流水线处理的新流API。

  • Date Time API - 改进的日期时间API。

  • Optional - 强调正确处理空值的最佳实践。

  • Nashorn, JavaScript Engine - 用于执行JavaScript代码的基于Java的引擎。

除了这些新功能之外,还有很多功能增强功能都是在编译器和JVM级别下完成的。

以下代码使用Java 8 lambda表达式对字符串列表进行排序:

//sort using java 8
private void sortUsingJava8(List<String> names) {
  Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
}

lambda表达式的特征在于以下语法 -

parameter −> expression body

以下是lambda表达式的重要特征 -

  • Optional type declaration - 无需声明参数类型。 编译器可以从参数的值推断出相同的值。

  • Optional parenthesis around parameter - 无需在括号中声明单个参数。 对于多个参数,需要括号。

  • Optional curly braces - 如果主体包含单个语句,则无需在表达式主体中使用花括号。

  • Optional return keyword - 如果正文具有单个表达式以返回值,则编译器会自动返回该值。 需要使用大括号来表示表达式返回一个值。

Lambda表达式主要用于定义功能接口的内联实现,即仅具有单个方法的接口。 在上面的例子中,我们使用了各种类型的lambda表达式来定义MathOperation接口的操作方法。 然后我们定义了GreetingService的sayMessage的实现。

Lambda表达式消除了对匿名类的需求,并为Java提供了非常简单但功能强大的函数编程功能。

使用lambda表达式,您可以引用最终变量或有效最终变量(仅分配一次)。 如果第二次为变量赋值,则Lambda表达式会抛出编译错误。

方法引用有助于通过名称指向方法。 使用::(双冒号)符号描述方法参考。 方法参考可用于指出以下类型的方法 -

  • 静态方法

  • 实例方法

  • 使用new运算符的构造函数(TreeSet :: new)

System.out :: println方法是对System类的out对象的println方法的静态方法引用。

功能界面具有单一功能。 例如,具有单个方法'compareTo'的Comparable接口用于比较目的。 Java 8定义了许多在lambda表达式中广泛使用的函数接口。

它表示一个接受两个输入参数的操作,并且不返回任何结果。

它表示一个接受两个参数并产生结果的函数。

它表示对两个相同类型的操作数的操作,产生与操作数相同类型的结果。

它表示两个参数的谓词(布尔值函数)。

它代表布尔值结果的供应商。

它表示接受单个输入参数并且不返回任何结果的操作。

它表示对两个双值操作数的运算并产生双值结果。

它表示接受单个双值参数并且不返回任何结果的操作。

它表示接受双值参数并生成结果的函数。

它表示一个双值参数的谓词(布尔值函数)。

它代表了双重价值结果的供应商。

它表示一个函数,它接受一个双值参数并产生一个int值结果。

它表示一个函数,它接受一个双值参数并产生一个长值结果。

它表示对单个双值操作数的操作,该操作产生双值结果。

它表示接受一个参数并生成结果的函数。

它表示对两个int值操作数的操作,并产生一个int值结果。

它表示接受单个int值参数并且不返回任何结果的操作。

它表示一个接受int值参数并生成结果的函数。

它表示一个int值参数的谓词(布尔值函数)。

它代表了int值结果的供应商。

它表示一个函数,它接受一个int值参数并产生一个双值结果。

它表示一个函数,它接受一个int值参数并产生一个长值结果。

它表示对单个int值操作数的操作,该操作数生成int值结果。

它表示对两个长值操作数的操作,并产生一个长值结果。

它表示接受单个长值参数并且不返回任何结果的操作。

它表示一个接受长值参数并产生结果的函数。

它表示一个长值参数的谓词(布尔值函数)。

它代表了长期价值的供应商。

它表示一个函数,它接受一个长值参数并产生一个双值结果。

它表示一个函数,它接受一个长值参数并产生一个int值结果。

它表示对单个长值操作数的操作,该操作产生长值结果。

它表示接受对象值和双值参数的操作,并且不返回任何结果。

它表示接受对象值和int值参数的操作,并且不返回任何结果。

它表示接受对象值和长值参数的操作,并且不返回任何结果。

它表示一个参数的谓词(布尔值函数)。

它代表了结果的供应商。

它表示一个函数,它接受两个参数并产生一个双值结果。

它表示产生双值结果的函数。

它表示一个函数,它接受两个参数并产生一个int值结果。

它表示一个产生int值结果的函数。

它表示一个函数,它接受两个参数并产生一个长值结果。

它代表一个产生长值结果的函数。

它表示对单个操作数的操作,该操作产生与其操作数相同类型的结果。

使用java 8,接口可以在接口中具有函数的默认实现。

接口也可以使用Java 8以上的静态帮助器方法。

public interface vehicle {
   default void print() {
      System.out.println("I am a vehicle!");
   }
   static void blowHorn() {
      System.out.println("Blowing horn!!!");
   }
}

使用super关键字和接口名称。

interface Vehicle {
   default void print() {
      System.out.println("I am a vehicle!");
   }
}
class Car implements Vehicle {
   public void print() {
      Vehicle.super.print();                  
   }
}

使用界面的名称。

interface Vehicle {
   static void blowHorn() {
      System.out.println("Blowing horn!!!");
   }
}
class Car implements Vehicle {
   public void print() {
      Vehicle.blowHorn();                  
   }
}

Stream表示来自源的一系列对象,它支持聚合操作。

大多数流操作都返回流本身,以便可以对其结果进行流水线操作。 这些操作称为中间操作,它们的功能是获取输入,处理它们并将输出返回到目标。 collect()方法是一个终端操作,通常在流水线操作结束时出现,以标记流的结尾。

与需要显式迭代的集合相比,流操作在内部对提供的源元素进行迭代。

Stream提供了一种新方法'forEach'来迭代流的每个元素。

以下代码段显示如何使用forEach打印10个随机数。

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

'map'方法用于将每个元素映射到其对应的结果。

以下代码段使用map打印唯一的数字方块。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
//get list of unique squares
List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

“过滤器”方法用于根据标准消除元素。

以下代码段使用过滤器打印空字符串计数。

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//get count of empty string
int count = strings.stream().filter(string −> string.isEmpty()).count();

'limit'方法用于减小流的大小。

以下代码段显示了如何打印10个随机数。

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

'sorted'方法用于对流进行排序。

以下代码段显示如何按排序顺序打印10个随机数。

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

parallelStream是并行处理流的替代方案。 看一下使用parallelStream打印空字符串计数的以下代码段。

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
//get count of empty string
int count = strings.parallelStream().filter(string −> string.isEmpty()).count();
//It is very easy to switch between sequential and parallel streams.

收集器用于组合流的元素的处理结果。 收集器可用于返回列表或字符串。

List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("Filtered List: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("Merged String: " + mergedString);

在Java 8中,引入了统计信息收集器来计算流处理时的所有统计信息。

以下代码将打印列表中的最高编号。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = integers.stream().mapToInt((x) −> x).summaryStatistics();
System.out.println("Highest number in List : " + stats.getMax());

以下代码将打印列表中的最高编号。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = integers.stream().mapToInt((x) −> x).summaryStatistics();
System.out.println("Lowest number in List : " + stats.getMin());
<p></p>

以下代码将打印列表中存在的所有数字的总和。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = integers.stream().mapToInt((x) −> x).summaryStatistics();
System.out.println("Sum of all numbers : " + stats.getSum());

以下代码将打印列表中存在的所有数字的平均值。

List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = integers.stream().mapToInt((x) −> x).summaryStatistics();
System.out.println("Average of all numbers : " + stats.getAverage());

可选是一个容器对象,用于包含非null对象。 可选对象用于表示缺少值的null。 此类具有各种实用程序方法,以便于代码将值处理为“可用”或“不可用”,而不是检查空值。 它在Java 8中引入,类似于Guava中的Optional。

使用Java 8,Nashorn,引入了一个大大改进的javascript引擎,以取代现有的Rhino。 Nashorn提供2到10倍的性能,因为它直接编译内存中的代码并将字节码传递给JVM。 Nashorn使用Java 7中引入的invokedynamics功能来提高性能。

对于Nashorn引擎,JAVA 8引入了一个新的命令行工具jjs,用于在控制台执行javascript代码。

是! 使用ScriptEngineManager,可以在Java中调用和解释JavaScript代码。

本地 - 简化的日期时间API,没有时区处理的复杂性。

Zoned - 专门的日期时间API,用于处理各种时区。

在Java 8中添加了java.time.temporal.ChronoUnit枚举,以替换旧API中使用的整数值来表示日,月等。

以下代码使用本地日期时间api获取当前日期 -

//Get the current date
LocalDate today = LocalDate.now();
System.out.println("Current date: " + today);

以下代码使用本地日期时间api将当前日期添加1周 -

//add 1 week to the current date
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("Next week: " + nextWeek);

以下代码使用本地日期时间api将当前日期添加1个月:

//add 1 month to the current date
LocalDate today = LocalDate.now();
LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS);
System.out.println("Next month: " + nextMonth);

以下代码使用本地日期时间api将当前日期添加1年 -

//add 1 year to the current date
LocalDate today = LocalDate.now();
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("Next year: " + nextYear);

以下代码使用本地日期时间api将当前日期添加10年 -

//add 10 years to the current date
LocalDate today = LocalDate.now();
LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES);
System.out.println("Date after ten year: " + nextDecade);

下面的代码在下周二使用java8进行 -

//get the next tuesday
LocalDate today = LocalDate.now();
LocalDate nextTuesday = today.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
System.out.println("Next Tuesday on : " + nextTuesday);

以下代码使用java8获得下个月的第二个星期六 -

//get the second saturday of next month
LocalDate firstInYear = LocalDate.of(date1.getYear(),date1.getMonth(), 1);
LocalDate secondSaturday = firstInYear.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)).with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
System.out.println("Second Saturday on : " + secondSaturday);

以下代码以毫秒为单位获取当前日期的瞬间 -

//Get the instant of current date in terms of milliseconds
Instant now = currentDate.toInstant();

以下代码使用毫秒级的时间获取本地日期时间的瞬间 -

Instant now = currentDate.toInstant();
ZoneId currentZone = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(now, currentZone);
System.out.println("Local date: " + localDateTime);

以下代码使用时间毫秒来获取分区日期时间的瞬间 -

Instant now = currentDate.toInstant();
ZoneId currentZone = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, currentZone);
System.out.println("Zoned date: " + zonedDateTime);

static class Base64.Decoder - 该类使用RFC 4648和RFC 2045中指定的Base64编码方案实现解码字节数据的解码器。

static class Base64.Encoder - 此类实现一个编码器,用于使用RFC 4648和RFC 2045中指定的Base64编码方案对字节数据进行编码。

Base64类的getDecoder()方法返回使用Basic类型base64编码方案解码的Base64.Decoder。

Base64类的getEncoder()方法返回使用Basic类型base64编码方案进行编码的Base64.Encoder。

Base64类的getMimeDecoder()方法返回使用MIME类型base64解码方案解码的Base64.Decoder。

Base64类的getMimeEncoder()方法返回使用MIME类型base64编码方案进行编码的Base64.Encoder。

Base64类的getUrlDecoder()方法返回一个Base64.Decoder,它使用URL和Filename安全类型base64编码方案进行解码。

Base64类的getUrlEncoder()方法返回一个Base64.Encoder,它使用URL和Filename安全类型base64编码方案进行编码。

接下来是什么 (What is Next?)

此外,您可以查看您对该主题所做的过去作业,并确保您能够自信地说出这些作业。 如果你更新鲜,那么面试官不会指望你会回答非常复杂的问题,而是你必须使你的基本概念非常强大。