上一篇:Java的8 Base64编码 下一篇:Java 8相关资料

Java 8快速指南

Java 8 - 概述

JAVA 8 is a major feature release of JAVA programming language development. Its initial version was released on 18 March 2014. With the Java 8 release, Java provided supports for functional programming, new JavaScript engine, new APIs for date time manipulation, new streaming API, etc.

New Features

  • Lambda expression − Adds functional processing capability to Java.

  • Method references − Referencing functions by their names instead of invoking them directly. Using functions as parameter.

  • Default method − Interface to have default method implementation.

  • New tools − New compiler tools and utilities are added like ‘jdeps’ to figure out dependencies.

  • Stream API − New stream API to facilitate pipeline processing.

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

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

  • Nashorn,JavaScript Engine - 一个基于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);
   }
	
   private void sortUsingJava7(List<String> names){
      //sort using java 7
      Collections.sort(names, new Comparator<String>() {
         @Override
         public int compare(String s1, String s2) {
            return s1.compareTo(s2);
         }
      });
   }
	
   private void sortUsingJava8(List<String> names){
      //sort using java 8
      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 - 环境设置

尝试在线OPtion

我们已经在线设置了Java编程环境,因此可以在线编译和执行所有可用的示例。你可以学习的同时,在线验证程序。随意修改任何示例并在线执行。

使用我们的在线编译器尝试以下示例

public class MyFirstJavaProgram {
   public static void main(String []args) {
      System.out.println("Hello World");
   }
}

对于本教程中给出的大多数示例,您将在右上角的网站代码部分找到一个Try it选项,该部分将带您进入在线编译器。所以只是利用它,享受你的学习。

本地环境设置

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

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

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

按照说明下载Java,并运行.exe在您的机器上安装Java。在机器上安装Java之后,您需要设置环境变量来指向正确的安装目录。

设置Windows 2000 / XP的路径

假设您已经在c: Program Files java jdk目录中安装了Java:

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

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

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

设置Windows 95/98 / ME的路径

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

  • 编辑"C: autoexec.bat"文件,并在最后添加以下行 - "SET PATH =%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。但是现在,您可以考虑以下之一 -

Java 8 - Lambda表达式

Lambda表达式在Java 8中被引入,被称为Java 8的最大特征.Lambda表达式有助于功能编程,并且简化了开发工作。

用法

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

parameter -> expression body

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

  • 可选类型声明 - 不需要声明参数的类型。编译器可以从参数的值推断相同的值。

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

  • 可选的花括号 - 如果正文包含单个语句,则无需在表达式正文中使用花括号。

  • 可选返回关键字 - 如果正文具有单个表达式以返回值,编译器将自动返回该值。需要花括号表示表达式返回值。

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));
		
      //with parenthesis
      GreetingService greetService1 = message ->
      System.out.println("Hello " + message);
		
      //without 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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

它应该产生以下输出 -

Hello! Mahesh

Java 8 - 方法参考

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

  • 静态方法
  • 实例方法
  • 使用新的运算符的构造函数(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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

它应该产生以下输出 -

Mahesh
Suresh
Ramesh
Naresh
Kalpesh

Java 8 - 功能界面

功能界面具有单一的功能。例如,使用具有单个方法“compareTo”的Comparable接口进行比较。Java 8已经定义了很多功能接口,可以在lambda表达式中广泛使用。以下是java.util.Function包中定义的功能接口的列表。

编号 接口和说明
1 BiConsumer <T,U>

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

2 BiFunction <T,U,R>

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

3 BinaryOperator <T>

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

4 BiPredicate <T,U>

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

5 布尔供应商

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

6 消费者<T>

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

7 DoubleBinaryOperator

代表对两个双值操作数的操作,并产生double值。

8 DoubleConsumer

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

9 双功能<R>

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

10 DoublePredicate

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

11 DoubleSupplier

代表double业绩的供应商。

12 DoubleToIntFunction

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

13 DoubleToLongFunction

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

14 DoubleUnaryOperator

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

15 功能<T,R>

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

16 IntBinaryOperator

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

17 IntConsumer

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

18 IntFunction <R>

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

19 IntPredicate

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

20 IntSupplier

代表着一个有价值的结果供应商。

21 IntToDoubleFunction

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

22 IntToLongFunction

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

23 IntUnaryOperator

表示对单个int值操作数产生一个int值的结果的操作。

24 LongBinaryOperator

代表对两个长期操作数的操作,并产生长期的结果。

25 LongConsumer

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

26 LongFunction <R>

表示接受长期参数并产生结果的函数。

27 LongPredicate

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

28 LongSupplier

代表着长期业绩的供应商。

29 LongToDoubleFunction

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

30 LongToIntFunction

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

31 LongUnaryOperator

代表产生长期效果的单个长期操作数的操作。

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 ToBongBiFunction <T,U>

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

42 ToLongFunction <T>

表示产生长期效果的函数。

43 UnaryOperator <T>

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

功能界面示例

Predicate <T>接口是一个功能界面,方法test(Object)返回一个布尔值。该接口表示对象被测试为true或false。

使用您所选择的任何编辑器(例如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接口,它接受一个输入并返回Boolean。

验证结果

使用javac编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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 {
   default void print(){
      System.out.println("I am a four wheeler car vehicle!");
   }
}

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

public class car implements vehicle, fourWheeler {
   default 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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

它应该产生以下输出 -

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

Java 8 - Streams

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

SELECT max(salary),employee_id,employee_name FROM Employee

上述SQL表达式自动返回最高受薪雇员的详细信息,而不对开发人员的结尾进行任何计算。在Java中使用集合框架,开发人员必须使用循环并进行重复检查。另一个问题是效率; 由于多核处理器可以放心使用,因此Java开发人员必须编写并行代码处理,这可能非常容易出错。

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

什么是流?

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

  • 元素序列 - 流以顺序方式提供特定类型的元素集合。流根据需要获取/计算元素。它从不存储元素。

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

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

  • 流水线 - 大多数流操作返回流本身,以便其结果可以流水线化。这些操作称为中间操作,它们的功能是输入,处理它们并将输出返回到目标。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());

forEach

Stream提供了一种新的方法“forEach”来迭代流的每个元素。以下代码段显示如何使用forEach打印10个随机数。

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

地图

“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());

过滤

“过滤器”方法用于根据标准消除元素。以下代码段使用过滤器打印空字符string的计数。

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是用于并行处理的流的替代。看看下面的代码段,使用parallelStream打印一个空字符string的数量。

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

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

收藏家

收集器用于将处理结果与流的元素相结合。收集器可用于返回列表或字符string。

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());
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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Testeras,

$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 - 可选类

可选是用于包含非空对象的容器对象。可选对象用于表示null,缺少值。这个类有各种各样的实用方法,以方便代码处理值为"可用"或"不可用",而不是检查空值。它在Java 8中引入,与Guava中的可选项相似。

Class宣言

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

public final class Optional<T>
extends Object

类方法

编号 方法和说明
1 static <T>可选<T> empty()

返回一个空的可选实例。

2 boolean equals(Object obj)

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

3 可选的<T>过滤器(谓词<?super <T>谓词)

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

4 <U>可选<U> flatMap(功能<?super T,可选<U>映射器)

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

5 T get()

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

6 int hashCode()

返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。

7 void ifPresent(Consumer <?super T> consumer)

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

8 boolean isPresent()

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

9 <U>可选<U> map(Function <?super T,?extends U> mapper)

如果存在值,则将提供的映射函数应用于其中,如果结果为非空,则返回一个可选描述结果。

10 静态<T>可选<T>(T值)

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

11 static <T>可选<T> ofNullable(T value)

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

12 T或Else(T other)

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

13 T或ElseGet(供应商<?延伸T>其他)

返回值(如果存在),否则调用其他值并返回该调用的结果。

14 <X extends Throwable> T orElseThrow(Supplier <?extends X> exceptionSupplier)

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

15 String toString()

返回此可选的非空字符string表示,适用于调试。

这个类继承下面的类的方法 -

  • 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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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中引入以提高性能。

jjs

对于犀牛发动机,JAVA 8引入了新的命令行工具,JJS,在控制台执行JavaScript代码。

解释js文件

在c:> JAVA文件夹中创建并保存文件sample.js

sample.js

print("Hello World!");

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

$jjs sample.js

它将产生以下输出:

Hello World!

jjs在交互模式

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

$jjs
jjs> print("Hello, World!")
Hello, World!
jjs> quit()
>>

通过参数

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

$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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

应该产生以下结果 -

Mahesh
12

从JavaScript调用Java

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

在c:> JAVA文件夹中创建并保存sample.js

sample.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);

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

$jjs sample.js

它应该产生以下输出 -

78952000000000000003.20

Java 8 - 新日期/时间API

使用Java 8,引入了一个新的Date-Time API,以涵盖旧的日期时间API的以下缺点。

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

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

  • 困难的时区处理 - 开发人员必须编写大量代码来处理时区问题。新的API已经开发出了保持范围特定的设计。

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

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

  • 分区 - 处理各种时区的专用日期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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

它应该产生以下输出 -

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

计时单位枚举

java.time.temporal.ChronoUnit枚举被添加到Java 8中以替换旧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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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.LocalDate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

应该产生以下结果 -

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

向后兼容性

将一个toInstant()方法添加到原始的Date和Calendar对象中,可以将它们转换为新的Date-Time API。使用一个Instant(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编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$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"作为行分隔符。编码输出的末尾没有行分隔符。

嵌套类

编号 嵌套类和说明
1 静态类Base64.Decoder

该类使用RFC 4648和RFC 2045中规定的Base64编码方案来实现用于解码字节数据的解码器。

2 静态类Base64.Encoder

该类使用RFC 4648和RFC 2045中规定的Base64编码方案来实现用于编码字节数据的编码器。

方法

编号 方法名称和说明
1 static Base64.Decoder getDecoder()

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

2 static Base64.Encoder getEncoder()

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

3 static Base64.Decoder getMimeDecoder()

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

4

static Base64.Encoder getMimeEncoder()

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

5 static Base64.Encoder getMimeEncoder(int lineLength,byte [] lineSeparator)

返回Base64.Encoder,它使用具有指定行长度和行分隔符的MIME类型base64编码方案进行编码。

6 static Base64.Decoder getUrlDecoder()

返回使用URL和Filename安全类型base64编码方案进行解码的Base64.Decoder。

7 static Base64.Encoder getUrlEncoder()

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

方法继承

这个类继承下面的类的方法 -

  • java.lang.Object

Base64示例

使用您所选择的任何编辑器,使用C:/> JAVA创建以下Java程序。

Java8Tester.java

import java.util.Base64;
import java.util.UUID;
import java.io.UnsupportedEncodingException;

public class HelloWorld {
   public static void main(String args[]){
      try {
		
         // Encode using basic encoder
         String base64encodedString = Base64.getEncoder().encodeToString("TutorialsPoint?java8".getBytes("utf-8"));
         System.out.println("Base64 Encoded String (Basic) :" + base64encodedString);
		
         // Decode
         byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
		
         System.out.println("Original String: "+new String(base64decodedBytes, "utf-8"));
         base64encodedString = Base64.getUrlEncoder().encodeToString("TutorialsPoint?java8".getBytes("utf-8"));
         System.out.println("Base64 Encoded String (URL) :" + base64encodedString);
		
         StringBuilder stringBuilder = new StringBuilder();
		
         for (int i = 0; i < 10; ++i) {
            stringBuilder.append(UUID.randomUUID().toString());
         }
		
         byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
         String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
         System.out.println("Base64 Encoded String (MIME) :"+mimeEncodedString);
      }catch(UnsupportedEncodingException e){
         System.out.println("Error :"+e.getMessage());
      }
   }
}

验证结果

使用javac编译器编译,如下所示:

$javac Java8Tester.java

现在运行Java8Tester如下 -

$java Java8Tester

它应该产生以下输出 -

Base64 Encoded String (Basic) :VHV0b3JpYWxzUG9pbnQ/amF2YTg=
Original String: TutorialsPoint?java8
Base64 Encoded String (URL) :VHV0b3JpYWxzUG9pbnQ_amF2YTg=
Base64 Encoded String (MIME) :ZWJjY2YzZWUtYmUwZC00Yjg1LTlkYjUtNWUyMzBlNWI
4ZGQ4ZjE1NGJmMjEtNTdkNi00YzM1LTg4
MzYtNDZlYzNhZDM2NTdkZmQzY2RiNzMtMTU1OC00ZjBmLWFmZGQtM2YyZWU3MDYzZjQwNzVhY
WQ0
ODctZWEyZS00YzM2LWEyZmUtOGVkMmNjMGNmZGM3MTg5YWUyZGQtMzg4MS00M2NkLWI2NDEtZ
jNh
Zjk2OGIxZDU2YzkzODZlYTUtNjljNC00ZmIyLTkzYTQtMzVlOTFlNjdlY2E0MDcwNWExMWItM
mE4
Yy00OTljLTg2NmItMjE3ZTZmMmIyY2NiNzI2MjAwZWQtMjI0NC00YzJhLWJiMGItOTczMDJkM
zIx
NGFkY2QyZmVhODItNmUyOS00MWNjLWFlODItNzdmNzRhYmQ4NGU5ZGQ3ZjY3NzktZjgwYi00M
zlk
LTlmNDgtOTNlNTIwYzIzZDcy

Copyright © 2002-2017 vue5.com 版权所有

Top