Java 8 - 快速指南


Java 8 - 概述

JAVA 8是JAVA编程语言开发的一个主要功能版本。它的初始版本于 2014 年 3 月 18 日发布。随着 Java 8 的发布,Java 提供了对函数式编程、新的 JavaScript 引擎、用于日期时间操作的新 API、新的流 API 等的支持。

新功能

  • Lambda 表达式- 为 Java 添加函数处理能力。

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

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

  • 新工具- 添加了新的编译器工具和实用程序,例如“jdeps”以找出依赖关系。

  • Stream API - 新的流API以促进管道处理。

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

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

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

考虑以下代码片段。

现场演示
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import java.util.Comparator;

public class Java8Tester {

   public static void main(String args[]) {
   
      List<String> names1 = new ArrayList<String>();
      names1.add("Mahesh ");
      names1.add("Suresh ");
      names1.add("Ramesh ");
      names1.add("Naresh ");
      names1.add("Kalpesh ");
		
      List<String> names2 = new ArrayList<String>();
      names2.add("Mahesh ");
      names2.add("Suresh ");
      names2.add("Ramesh ");
      names2.add("Naresh ");
      names2.add("Kalpesh ");
		
      Java8Tester tester = new Java8Tester();
      System.out.println("Sort using Java 7 syntax: ");
		
      tester.sortUsingJava7(names1);
      System.out.println(names1);
      System.out.println("Sort using Java 8 syntax: ");
		
      tester.sortUsingJava8(names2);
      System.out.println(names2);
   }
   
   //sort using java 7
   private void sortUsingJava7(List<String> names) {   
      Collections.sort(names, new Comparator<String>() {
         @Override
         public int compare(String s1, String s2) {
            return s1.compareTo(s2);
         }
      });
   }
   
   //sort using java 8
   private void sortUsingJava8(List<String> names) {
      Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
   }
}

运行程序得到如下结果。

Sort using Java 7 syntax:
[ Kalpesh Mahesh Naresh Ramesh Suresh ]
Sort using Java 8 syntax:
[ Kalpesh Mahesh Naresh Ramesh Suresh ]

这里的sortUsingJava8()方法使用排序函数并以 lambda 表达式作为参数来获取排序标准。

Java 8 - 环境设置

本地环境设置

如果您想设置自己的 Java 编程语言环境,那么本节将指导您完成整个过程。请按照以下步骤设置您的 Java 环境。

Java SE 可以从以下链接免费下载 -

https://www.oracle.com/technetwork/java/javase/downloads/index-jsp-138363.html

您可以根据您的操作系统下载一个版本。

按照说明下载 Java,然后运行​​.exe以在您的计算机上安装 Java。在计算机上安装 Java 后,您需要设置环境变量以指向正确的安装目录。

设置 Windows 2000/XP 的路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 右键单击“我的电脑”并选择“属性”。

  • 单击“高级”选项卡下的“环境变量”按钮。

  • 现在,更改“Path”变量,使其也包含 Java 可执行文件的路径。例如,如果路径当前设置为“C:\WINDOWS\SYSTEM32”,则将路径更改为“C:\WINDOWS\SYSTEM32;c:\Program Files\java\jdk\bin”。

设置Windows 95/98/ME的路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 编辑“C:\autoexec.bat”文件并在末尾添加以下行 -

    设置路径=%PATH%;C:\Program Files\java\jdk\bin

设置 Linux、UNIX、Solaris、FreeBSD 的路径

应将环境变量 PATH 设置为指向 Java 二进制文件的安装位置。如果您在执行此操作时遇到问题,请参阅您的 shell 文档。

例如,如果您使用 bash 作为 shell,那么您可以在 '.bashrc:export PATH=/path/to/java:$PATH' 的末尾添加以下行

流行的 Java 编辑器

要编写 Java 程序,您需要一个文本编辑器。市场上还有更复杂的 IDE。但现在,您可以考虑以下其中一项 -

  • 记事本- 在 Windows 计算机上,您可以使用任何简单的文本编辑器,例如记事本(本教程推荐)或 TextPad。

  • Netbeans - 它是一个开源且免费的 Java IDE。可以从https://netbeans.org/index.html下载。

  • Eclipse - 它也是由 Eclipse 开源社区开发的 Java IDE,可以从https://www.eclipse.org/下载。

Java 8 - Lambda 表达式

Java 8 中引入了 Lambda 表达式,被誉为 Java 8 最大的特性。Lambda 表达式方便了函数式编程,大大简化了开发。

句法

lambda 表达式具有以下语法特征。

parameter -> expression body

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

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

  • 参数周围的可选括号- 无需在括号中声明单个参数。对于多个参数,需要括号。

  • 可选大括号- 如果表达式主体包含单个语句,则无需在表达式主体中使用大括号。

  • 可选 return 关键字- 如果主体具有单个表达式来返回值,则编译器会自动返回值。需要大括号来指示表达式返回值。

Lambda 表达式示例

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester tester = new Java8Tester();
		
      //with type declaration
      MathOperation addition = (int a, int b) -> a + b;
		
      //with out type declaration
      MathOperation subtraction = (a, b) -> a - b;
		
      //with return statement along with curly braces
      MathOperation multiplication = (int a, int b) -> { return a * b; };
		
      //without return statement and without curly braces
      MathOperation division = (int a, int b) -> a / b;
		
      System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
      System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
      System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
      System.out.println("10 / 5 = " + tester.operate(10, 5, division));
		
      //without parenthesis
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
		
      //with parenthesis
      GreetingService greetService2 = (message) ->
      System.out.println("Hello " + message);
		
      greetService1.sayMessage("Mahesh");
      greetService2.sayMessage("Suresh");
   }
	
   interface MathOperation {
      int operation(int a, int b);
   }
	
   interface GreetingService {
      void sayMessage(String message);
   }
	
   private int operate(int a, int b, MathOperation mathOperation) {
      return mathOperation.operation(a, b);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Mahesh
Hello Suresh

以下是上述示例中需要考虑的要点。

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

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

范围

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

范围示例

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
public class Java8Tester {

   final static String salutation = "Hello! ";
   
   public static void main(String args[]) {
      GreetingService greetService1 = message -> 
      System.out.println(salutation + message);
      greetService1.sayMessage("Mahesh");
   }
	
   interface GreetingService {
      void sayMessage(String message);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

Hello! Mahesh

Java 8 - 方法参考

方法引用有助于通过名称指向方法。使用“::”符号描述方法引用。方法引用可用于指向以下类型的方法 -

  • 静态方法
  • 实例方法
  • 使用 new 运算符的构造函数 (TreeSet::new)

方法参考示例

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

import java.util.List;
import java.util.ArrayList;

public class Java8Tester {

   public static void main(String args[]) {
      List names = new ArrayList();
		
      names.add("Mahesh");
      names.add("Suresh");
      names.add("Ramesh");
      names.add("Naresh");
      names.add("Kalpesh");
		
      names.forEach(System.out::println);
   }
}

这里我们将 System.out::println 方法作为静态方法引用传递。

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

Mahesh
Suresh
Ramesh
Naresh
Kalpesh

Java 8 - 函数式接口

函数式接口具有单一的功能来展示。例如,具有单个方法“compareTo”的 Comparable 接口用于比较目的。Java 8 定义了许多函数式接口,广泛用于 lambda 表达式。以下是 java.util.Function 包中定义的函数接口列表。

先生。 接口及说明
1

BiConsumer<T,U>

表示接受两个输入参数且不返回结果的操作。

2

双函数<T,U,R>

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

3

二元运算符<T>

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

4

双谓词<T,U>

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

5

布尔供应商

代表布尔值结果的提供者。

6

消费者<T>

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

7

双二元运算符

表示对两个双值操作数进行运算并生成双值结果。

8

双重消费者

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

9

双功能<R>

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

10

双谓词

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

11

双供应商

代表双值结果的提供者。

12

DoubleToInt 函数

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

13

DoubleToLong 函数

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

14

双一元运算符

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

15

函数<T,R>

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

16

整数二元运算符

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

17 号

国际消费者

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

18

整数函数<R>

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

19

内部谓词

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

20

国际供应商

代表 int 值结果的提供者。

21

整数转双精度函数

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

22

IntToLong函数

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

23

整型一元运算符

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

24

长二元运算符

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

25

长消费者

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

26

长函数<R>

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

27

长谓词

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

28

长供应商

代表长期有价值的结果的提供者。

29

长到双功能

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

30

LongToInt函数

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

31

长一元运算符

表示对单个长值操作数进行的操作,该操作会生成长值结果。

32

ObjDoubleConsumer<T>

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

33

ObjIntConsumer<T>

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

34

ObjLongConsumer<T>

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

35

谓词<T>

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

36

供应商<T>

代表结果的提供者。

37

ToDoubleBiFunction<T,U>

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

38

ToDoubleFunction<T>

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

39

ToIntBiFunction<T,U>

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

40

ToIntFunction<T>

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

41

ToLongBi函数<T,U>

表示接受两个参数并生成长值结果的函数。

42

ToLong函数<T>

表示产生长值结果的函数。

43

一元运算符<T>

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

函数式接口示例

Predicate <T> 接口是一个函数式接口,其方法 test(Object) 返回布尔值。这个接口表示一个对象被测试为真或假。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Java8Tester {

   public static void main(String args[]) {
      List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
		
      // Predicate<Integer> predicate = n -> true
      // n is passed as parameter to test method of Predicate interface
      // test method will always return true no matter what value n has.
		
      System.out.println("Print all numbers:");
		
      //pass n as parameter
      eval(list, n->true);
		
      // Predicate<Integer> predicate1 = n -> n%2 == 0
      // n is passed as parameter to test method of Predicate interface
      // test method will return true if n%2 comes to be zero
		
      System.out.println("Print even numbers:");
      eval(list, n-> n%2 == 0 );
		
      // Predicate<Integer> predicate2 = n -> n > 3
      // n is passed as parameter to test method of Predicate interface
      // test method will return true if n is greater than 3.
		
      System.out.println("Print numbers greater than 3:");
      eval(list, n-> n > 3 );
   }
	
   public static void eval(List<Integer> list, Predicate<Integer> predicate) {

      for(Integer n: list) {

         if(predicate.test(n)) {
            System.out.println(n + " ");
         }
      }
   }
}

这里我们传递了 Predicate 接口,它接受单个输入并返回布尔值。

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

Print all numbers:
1
2
3
4
5
6
7
8
9
Print even numbers:
2
4
6
8
Print numbers greater than 3:
4
5
6
7
8
9

Java 8 - 默认方法

Java 8 引入了接口中默认方法实现的新概念。添加此功能是为了向后兼容,以便可以使用旧接口来利用 Java 8 的 lambda 表达式功能。

例如,“List”或“Collection”接口没有“forEach”方法声明。因此,添加这样的方法只会破坏集合框架的实现。Java 8引入了默认方法,使得List/Collection接口可以有forEach方法的默认实现,而实现这些接口的类不需要实现相同的方法。

句法

public interface vehicle {

   default void print() {
      System.out.println("I am a vehicle!");
   }
}

多重默认

对于接口中的默认函数,一个类可能会实现两个具有相同默认方法的接口。以下代码解释了如何解决这种歧义。

public interface vehicle {

   default void print() {
      System.out.println("I am a vehicle!");
   }
}

public interface fourWheeler {

   default void print() {
      System.out.println("I am a four wheeler!");
   }
}

第一个解决方案是创建一个自己的方法来覆盖默认实现。

public class car implements vehicle, fourWheeler {

   public void print() {
      System.out.println("I am a four wheeler car vehicle!");
   }
}

第二种解决方案是使用 super 调用指定接口的默认方法。

public class car implements vehicle, fourWheeler {

   public void print() {
      vehicle.super.print();
   }
}

静态默认方法

从 Java 8 开始,接口还可以具有静态帮助器方法。

public interface vehicle {

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

默认方法示例

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
public class Java8Tester {

   public static void main(String args[]) {
      Vehicle vehicle = new Car();
      vehicle.print();
   }
}

interface Vehicle {

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

interface FourWheeler {

   default void print() {
      System.out.println("I am a four wheeler!");
   }
}

class Car implements Vehicle, FourWheeler {

   public void print() {
      Vehicle.super.print();
      FourWheeler.super.print();
      Vehicle.blowHorn();
      System.out.println("I am a car!");
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

I am a vehicle!
I am a four wheeler!
Blowing horn!!!
I am a car!

Java 8 - 流

Stream是Java 8中引入的一个新的抽象层。使用stream,您可以以类似于SQL语句的声明式方式处理数据。例如,考虑以下 SQL 语句。

SELECT max(salary), employee_id, employee_name FROM Employee

上面的 SQL 表达式自动返回最高薪员工的详细信息,而无需在开发人员端进行任何计算。使用Java中的集合框架,开发人员必须使用循环并进行重复检查。另一个问题是效率;由于多核处理器可以轻松使用,Java 开发人员必须编写非常容易出错的并行代码处理。

为了解决此类问题,Java 8 引入了流的概念,使开发人员能够以声明方式处理数据并利用多核架构,而无需为其编写任何特定代码。

什么是流?

Stream 表示来自源的对象序列,支持聚合操作。以下是流的特征 -

  • 元素序列- 流以顺序方式提供一组特定类型的元素。流按需获取/计算元素。它从不存储元素。

  • Source - Stream 将集合、数组或 I/O 资源作为输入源。

  • 聚合操作- Stream 支持聚合操作,如过滤器、映射、限制、减少、查找、匹配等。

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

  • 自动迭代- 流操作在提供的源元素上进行内部迭代,这与需要显式迭代的集合相反。

生成流

在 Java 8 中,Collection 接口有两种方法来生成 Stream。

  • Stream() - 返回一个将集合作为其源的顺序流。

  • parallelStream() - 返回一个并行流,考虑集合作为其源。

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

对于每个

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”方法用于减小流的大小。以下代码段显示如何使用 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 是用于并行处理的流的替代方案。看一下下面的代码段,它使用并行流打印空字符串的计数。

List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");

//get count of empty string
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();

在顺序流和并行流之间切换非常容易。

收藏家

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

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 numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);

IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();

System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage());

流示例

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.Map;

public class Java8Tester {

   public static void main(String args[]) {
      System.out.println("Using Java 7: ");
		
      // Count empty strings
      List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
      System.out.println("List: " +strings);
      long count = getCountEmptyStringUsingJava7(strings);
		
      System.out.println("Empty Strings: " + count);
      count = getCountLength3UsingJava7(strings);
		
      System.out.println("Strings of length 3: " + count);
		
      //Eliminate empty string
      List<String> filtered = deleteEmptyStringsUsingJava7(strings);
      System.out.println("Filtered List: " + filtered);
		
      //Eliminate empty string and join using comma.
      String mergedString = getMergedStringUsingJava7(strings,", ");
      System.out.println("Merged String: " + mergedString);
      List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
		
      //get list of square of distinct numbers
      List<Integer> squaresList = getSquares(numbers);
      System.out.println("Squares List: " + squaresList);
      List<Integer> integers = Arrays.asList(1,2,13,4,15,6,17,8,19);
		
      System.out.println("List: " +integers);
      System.out.println("Highest number in List : " + getMax(integers));
      System.out.println("Lowest number in List : " + getMin(integers));
      System.out.println("Sum of all numbers : " + getSum(integers));
      System.out.println("Average of all numbers : " + getAverage(integers));
      System.out.println("Random Numbers: ");
		
      //print ten random numbers
      Random random = new Random();
		
      for(int i = 0; i < 10; i++) {
         System.out.println(random.nextInt());
      }
		
      System.out.println("Using Java 8: ");
      System.out.println("List: " +strings);
		
      count = strings.stream().filter(string->string.isEmpty()).count();
      System.out.println("Empty Strings: " + count);
		
      count = strings.stream().filter(string -> string.length() == 3).count();
      System.out.println("Strings of length 3: " + count);
		
      filtered = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.toList());
      System.out.println("Filtered List: " + filtered);
		
      mergedString = strings.stream().filter(string ->!string.isEmpty()).collect(Collectors.joining(", "));
      System.out.println("Merged String: " + mergedString);
		
      squaresList = numbers.stream().map( i ->i*i).distinct().collect(Collectors.toList());
      System.out.println("Squares List: " + squaresList);
      System.out.println("List: " +integers);
		
      IntSummaryStatistics stats = integers.stream().mapToInt((x) ->x).summaryStatistics();
		
      System.out.println("Highest number in List : " + stats.getMax());
      System.out.println("Lowest number in List : " + stats.getMin());
      System.out.println("Sum of all numbers : " + stats.getSum());
      System.out.println("Average of all numbers : " + stats.getAverage());
      System.out.println("Random Numbers: ");
		
      random.ints().limit(10).sorted().forEach(System.out::println);
		
      //parallel processing
      count = strings.parallelStream().filter(string -> string.isEmpty()).count();
      System.out.println("Empty Strings: " + count);
   }
	
   private static int getCountEmptyStringUsingJava7(List<String> strings) {
      int count = 0;

      for(String string: strings) {
		
         if(string.isEmpty()) {
            count++;
         }
      }
      return count;
   }
	
   private static int getCountLength3UsingJava7(List<String> strings) {
      int count = 0;
		
      for(String string: strings) {
		
         if(string.length() == 3) {
            count++;
         }
      }
      return count;
   }
	
   private static List<String> deleteEmptyStringsUsingJava7(List<String> strings) {
      List<String> filteredList = new ArrayList<String>();
		
      for(String string: strings) {
		
         if(!string.isEmpty()) {
             filteredList.add(string);
         }
      }
      return filteredList;
   }
	
   private static String getMergedStringUsingJava7(List<String> strings, String separator) {
      StringBuilder stringBuilder = new StringBuilder();
		
      for(String string: strings) {
		
         if(!string.isEmpty()) {
            stringBuilder.append(string);
            stringBuilder.append(separator);
         }
      }
      String mergedString = stringBuilder.toString();
      return mergedString.substring(0, mergedString.length()-2);
   }
	
   private static List<Integer> getSquares(List<Integer> numbers) {
      List<Integer> squaresList = new ArrayList<Integer>();
		
      for(Integer number: numbers) {
         Integer square = new Integer(number.intValue() * number.intValue());
			
         if(!squaresList.contains(square)) {
            squaresList.add(square);
         }
      }
      return squaresList;
   }
	
   private static int getMax(List<Integer> numbers) {
      int max = numbers.get(0);
		
      for(int i = 1;i < numbers.size();i++) {
		
         Integer number = numbers.get(i);
			
         if(number.intValue() > max) {
            max = number.intValue();
         }
      }
      return max;
   }
	
   private static int getMin(List<Integer> numbers) {
      int min = numbers.get(0);
		
      for(int i= 1;i < numbers.size();i++) {
         Integer number = numbers.get(i);
		
         if(number.intValue() < min) {
            min = number.intValue();
         }
      }
      return min;
   }
	
   private static int getSum(List numbers) {
      int sum = (int)(numbers.get(0));
		
      for(int i = 1;i < numbers.size();i++) {
         sum += (int)numbers.get(i);
      }
      return sum;
   }
	
   private static int getAverage(List<Integer> numbers) {
      return getSum(numbers) / numbers.size();
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下结果 -

Using Java 7:
List: [abc, , bc, efg, abcd, , jkl]
Empty Strings: 2
Strings of length 3: 3
Filtered List: [abc, bc, efg, abcd, jkl]
Merged String: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
List: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Highest number in List : 19
Lowest number in List : 1
Sum of all numbers : 85
Average of all numbers : 9
Random Numbers:
-1279735475
903418352
-1133928044
-1571118911
628530462
18407523
-881538250
-718932165
270259229
421676854
Using Java 8:
List: [abc, , bc, efg, abcd, , jkl]
Empty Strings: 2
Strings of length 3: 3
Filtered List: [abc, bc, efg, abcd, jkl]
Merged String: abc, bc, efg, abcd, jkl
Squares List: [9, 4, 49, 25]
List: [1, 2, 13, 4, 15, 6, 17, 8, 19]
Highest number in List : 19
Lowest number in List : 1
Sum of all numbers : 85
Average of all numbers : 9.444444444444445
Random Numbers:
-1009474951
-551240647
-2484714
181614550
933444268
1227850416
1579250773
1627454872
1683033687
1798939493
Empty Strings: 2

Java 8 - 可选类

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

类别声明

以下是java.util.Optional<T>类的声明-

public final class Optional<T> extends Object

类方法

先生。 方法及说明
1

静态 <T> 可选 <T> 空()

返回一个空的可选实例。

2

布尔等于(对象 obj)

指示某个其他对象是否“等于”此可选对象。

3

可选<T>过滤器(谓词<?超级<T>谓词)

如果存在值并且该值与给定谓词匹配,则返回描述该值的可选值,否则返回空可选值。

4

<U> 可选<U> flatMap(Function<? super T,可选<U>> 映射器)

如果存在值,则会将提供的可选承载映射函数应用于该值,返回该结果,否则返回空的可选值。

5

获取()

如果此Optional中存在值,则返回该值,否则抛出NoSuchElementException。

6

int 哈希码()

返回当前值的哈希码值(如果有);如果不存在值,则返回 0(零)。

7

void ifPresent(Consumer<? super T> 消费者)

如果存在值,它将使用该值调用指定的使用者,否则不执行任何操作。

8

布尔值 isPresent()

如果存在值则返回 true,否则返回 false。

9

<U>可选<U>映射(函数<?super T,?extends U>映射器)

如果存在值,则对其应用提供的映射函数,如果结果非空,则返回描述结果的可选值。

10

static <T> 可选<T> of(T 值)

返回具有指定的当前非空值的可选值。

11

static <T> 可选<T> ofNullable(T 值)

如果非空,则返回描述指定值的可选值,否则返回空可选值。

12

T orElse(T 其他)

如果存在则返回值,否则返回其他值。

13

T orElseGet(Supplier<? extends T> other)

如果存在则返回该值,否则调用 other 并返回该调用的结果。

14

<X 扩展 Throwable> T 或 ElseThrow(Supplier<? 扩展 X> 异常供应商)

返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。

15

字符串转字符串()

返回此可选值的非空字符串表示形式,适合调试。

该类继承了以下类的方法 -

  • java.lang.Object

可选示例

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.util.Optional;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8Tester = new Java8Tester();
      Integer value1 = null;
      Integer value2 = new Integer(10);
		
      //Optional.ofNullable - allows passed parameter to be null.
      Optional<Integer> a = Optional.ofNullable(value1);
		
      //Optional.of - throws NullPointerException if passed parameter is null
      Optional<Integer> b = Optional.of(value2);
      System.out.println(java8Tester.sum(a,b));
   }
	
   public Integer sum(Optional<Integer> a, Optional<Integer> b) {
      //Optional.isPresent - checks the value is present or not
		
      System.out.println("First parameter is present: " + a.isPresent());
      System.out.println("Second parameter is present: " + b.isPresent());
		
      //Optional.orElse - returns the value if present otherwise returns
      //the default value passed.
      Integer value1 = a.orElse(new Integer(0));
		
      //Optional.get - gets the value, value should be present
      Integer value2 = b.get();
      return value1 + value2;
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

First parameter is present: false
Second parameter is present: true
10

Java 8 - Nashorn JavaScript

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

杰杰斯

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

解释js文件

创建文件example.js并将其保存在 c:\> JAVA 文件夹中。

示例.js

print('Hello World!');

打开控制台并使用以下命令。

C:\JAVA>jjs sample.js

它将产生以下输出:

Hello World!

jjs 交互模式

打开控制台并使用以下命令。

C:\JAVA>jjs
jjs> print("Hello, World!")
Hello, World!
jjs> quit()
>>

传递参数

打开控制台并使用以下命令。

C:\JAVA> jjs -- a b c
jjs> print('letters: ' +arguments.join(", "))
letters: a, b, c
jjs>

从 Java 调用 JavaScript

使用ScriptEngineManager,可以用Java调用和解释JavaScript代码。

例子

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.ScriptException;

public class Java8Tester {

   public static void main(String args[]) {
      ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
      ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");
		
      String name = "Mahesh";
      Integer result = null;
      
      try {
         nashorn.eval("print('" + name + "')");
         result = (Integer) nashorn.eval("10 + 2");
         
      } catch(ScriptException e) {
         System.out.println("Error executing script: "+ e.getMessage());
      }
      System.out.println(result.toString());
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下结果 -

Mahesh
12

从 JavaScript 调用 Java

以下示例说明了如何在 java 脚本中导入和使用 Java 类。

创建Sample.js并将其保存在 c:\> JAVA 文件夹中。

示例.js

var BigDecimal = Java.type('java.math.BigDecimal');

function calculate(amount, percentage) {

   var result = new BigDecimal(amount).multiply(new BigDecimal(percentage)).divide(
      new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_EVEN);
   
   return result.toPlainString();
}
var result = calculate(568000000000000000023,13.9);
print(result);

打开控制台并使用以下命令。

C:\JAVA>jjs sample.js

它应该产生以下输出 -

78952000000000000003.20

Java 8 - 新的日期/时间 API

Java 8 引入了新的日期时间 API,以弥补旧日期时间 API 的以下缺点。

  • 不是线程安全的- java.util.Date 不是线程安全的,因此开发人员在使用日期时必须处理并发问题。新的日期时间 API 是不可变的,并且没有 setter 方法。

  • 糟糕的设计- 默认日期从 1900 年开始,月份从 1 开始,日期从 0 开始,所以没有统一性。旧的 API 对于日期操作的直接方法较少。新的 API 为此类操作提供了许多实用方法。

  • 困难的时区处理- 开发人员必须编写大量代码来处理时区问题。新 API 的开发始终考虑到特定领域的设计。

Java 8 在 java.time 包下引入了一个新的日期时间 API。以下是java.time包中引入的一些重要类。

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

  • Zoned - 专门的日期时间 API 来处理各种时区。

本地日期时间 API

LocalDate/LocalTime 和 LocalDateTime 类简化了不需要时区的开发。让我们看看他们的实际行动。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 java 程序。

Java8Tester.java

现场演示
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.Month;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8tester = new Java8Tester();
      java8tester.testLocalDateTime();
   }
	
   public void testLocalDateTime() {
      // Get the current date and time
      LocalDateTime currentTime = LocalDateTime.now();
      System.out.println("Current DateTime: " + currentTime);
		
      LocalDate date1 = currentTime.toLocalDate();
      System.out.println("date1: " + date1);
		
      Month month = currentTime.getMonth();
      int day = currentTime.getDayOfMonth();
      int seconds = currentTime.getSecond();
		
      System.out.println("Month: " + month +"day: " + day +"seconds: " + seconds);
		
      LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
      System.out.println("date2: " + date2);
		
      //12 december 2014
      LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
      System.out.println("date3: " + date3);
		
      //22 hour 15 minutes
      LocalTime date4 = LocalTime.of(22, 15);
      System.out.println("date4: " + date4);
		
      //parse a string
      LocalTime date5 = LocalTime.parse("20:15:30");
      System.out.println("date5: " + date5);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

Current DateTime: 2014-12-09T11:00:45.457
date1: 2014-12-09
Month: DECEMBERday: 9seconds: 45
date2: 2012-12-10T11:00:45.457
date3: 2014-12-12
date4: 22:15
date5: 20:15:30

分区日期时间 API

当考虑时区时,将使用分区日期时间 API。让我们看看他们的实际行动。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.time.ZonedDateTime;
import java.time.ZoneId;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8tester = new Java8Tester();
      java8tester.testZonedDateTime();
   }
	
   public void testZonedDateTime() {
      // Get the current date and time
      ZonedDateTime date1 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]");
      System.out.println("date1: " + date1);
		
      ZoneId id = ZoneId.of("Europe/Paris");
      System.out.println("ZoneId: " + id);
		
      ZoneId currentZone = ZoneId.systemDefault();
      System.out.println("CurrentZone: " + currentZone);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

date1: 2007-12-03T10:15:30+05:00[Asia/Karachi]
ZoneId: Europe/Paris
CurrentZone: Etc/UTC

计时单位枚举

Java 8 中添加了 java.time.temporal.ChronoUnit 枚举,以替换旧 API 中用于表示日、月等的整数值。让我们看看它们的实际效果。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8tester = new Java8Tester();
      java8tester.testChromoUnits();
   }
	
   public void testChromoUnits() {
      //Get the current date
      LocalDate today = LocalDate.now();
      System.out.println("Current date: " + today);
		
      //add 1 week to the current date
      LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
      System.out.println("Next week: " + nextWeek);
		
      //add 1 month to the current date
      LocalDate nextMonth = today.plus(1, ChronoUnit.MONTHS);
      System.out.println("Next month: " + nextMonth);
		
      //add 1 year to the current date
      LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
      System.out.println("Next year: " + nextYear);
		
      //add 10 years to the current date
      LocalDate nextDecade = today.plus(1, ChronoUnit.DECADES);
      System.out.println("Date after ten year: " + nextDecade);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下结果 -

Current date: 2014-12-10
Next week: 2014-12-17
Next month: 2015-01-10
Next year: 2015-12-10
Date after ten year: 2024-12-10

期间和持续时间

Java 8 引入了两个专门的类来处理时间差异。

  • 周期- 它处理基于日期的时间量。

  • 持续时间- 它处理基于时间的时间量。

让我们看看他们的实际行动。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.time.temporal.ChronoUnit;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Duration;
import java.time.Period;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8tester = new Java8Tester();
      java8tester.testPeriod();
      java8tester.testDuration();
   }
	
   public void testPeriod() {
      //Get the current date
      LocalDate date1 = LocalDate.now();
      System.out.println("Current date: " + date1);
		
      //add 1 month to the current date
      LocalDate date2 = date1.plus(1, ChronoUnit.MONTHS);
      System.out.println("Next month: " + date2);
      
      Period period = Period.between(date2, date1);
      System.out.println("Period: " + period);
   }
	
   public void testDuration() {
      LocalTime time1 = LocalTime.now();
      Duration twoHours = Duration.ofHours(2);
		
      LocalTime time2 = time1.plus(twoHours);
      Duration duration = Duration.between(time1, time2);
		
      System.out.println("Duration: " + duration);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

Current date: 2014-12-10
Next month: 2015-01-10
Period: P-1M
Duration: PT2H

时间调节器

TemporalAdjuster 用于执行日期数学运算。例如,获取“该月的第二个星期六”或“下星期二”。让我们看看他们的实际行动。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.time.DayOfWeek;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8tester = new Java8Tester();
      java8tester.testAdjusters();
   }
	
   public void testAdjusters() {
      //Get the current date
      LocalDate date1 = LocalDate.now();
      System.out.println("Current date: " + date1);
		
      //get the next tuesday
      LocalDate nextTuesday = date1.with(TemporalAdjusters.next(DayOfWeek.TUESDAY));
      System.out.println("Next Tuesday on : " + nextTuesday);
		
      //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);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下结果 -

Current date: 2014-12-10
Next Tuesday on : 2014-12-16
Second Saturday on : 2014-12-13

向后兼容性

原始 Date 和 Calendar 对象中添加了 toInstant() 方法,可用于将它们转换为新的 Date-Time API。使用 ofInstant(Insant,ZoneId) 方法获取 LocalDateTime 或 ZonedDateTime 对象。让我们看看他们的实际行动。

使用您选择的任何编辑器(例如 C:\> JAVA)创建以下 Java 程序。

Java8Tester.java

现场演示
import java.time.LocalDateTime;
import java.time.ZonedDateTime;

import java.util.Date;

import java.time.Instant;
import java.time.ZoneId;

public class Java8Tester {

   public static void main(String args[]) {
      Java8Tester java8tester = new Java8Tester();
      java8tester.testBackwardCompatability();
   }
	
   public void testBackwardCompatability() {
      //Get the current date
      Date currentDate = new Date();
      System.out.println("Current date: " + currentDate);
		
      //Get the instant of current date in terms of milliseconds
      Instant now = currentDate.toInstant();
      ZoneId currentZone = ZoneId.systemDefault();
		
      LocalDateTime localDateTime = LocalDateTime.ofInstant(now, currentZone);
      System.out.println("Local date: " + localDateTime);
		
      ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(now, currentZone);
      System.out.println("Zoned date: " + zonedDateTime);
   }
}

验证结果

使用javac编译器编译该类,如下所示 -

C:\JAVA>javac Java8Tester.java

现在运行 Java8Tester,如下所示 -

C:\JAVA>java Java8Tester

它应该产生以下输出 -

Current date: Wed Dec 10 05:44:06 UTC 2014
Local date: 2014-12-10T05:44:06.635
Zoned date: 2014-12-10T05:44:06.635Z[Etc/UTC]

Java 8 - Base64

在 Java 8 中,Base64 终于得到了应有的回报。Java 8 现在具有用于 Base64 编码的内置编码器和解码器。在Java 8中,我们可以使用三种类型的Base64编码。

  • 简单- 输出映射到 A-Za-z0-9+/ 中的一组字符。编码器不会在输出中添加任何换行,解码器会拒绝除 A-Za-z0-9+/ 之外的任何字符。

  • URL - 输出映射到 A-Za-z0-9+_ 中的字符集。输出是 URL 和文件名安全的。

  • MIME - 输出映射为 MIME 友好格式。输出以每行不超过 76 个字符的形式表示,并使用回车符 '\r' 后跟换行符 '\n' 作为行分隔符。编码输出末尾不存在行分隔符。

嵌套类