目录
-
-
-
1. Java8新特性_简介
-
2. 为什么使用 Lambda 表达式
-
3. Java8新特性_Lambda 基础语法
-
4. Java8新特性_Lambda 练习
-
5. Java8新特性_四大内置核心函数式接口
-
6. Java8新特性_方法引用与构造器引用
-
7. Java8新特性_创建 Stream
-
8. Java8新特性_Stream_筛选与切片
-
9. Java8新特性_Stream_映射
-
10. Java8新特性_Stream_排序
-
11. Java8新特性_Stream_查找与匹配
-
12. Java8新特性_Stream_归约与收集
-
13. Java8新特性_Stream API 练习
-
14. Java8新特性_并行流与串行流
-
15. Java8新特性_Optional 容器类
-
16. Java8新特性_接口中的默认方法与静态方法
-
17. Java8新特性_传统时间格式化的线程安全问题
-
18. Java8新特性_新时间与日期 API-本地时间与时间戳
-
19. Java8新特性_新时间和日期 API-时间校正器
-
20. Java8新特性_新时间和日期 API-时间格式化与时区的处理
-
21. Java8新特性_重复注解与类型注解
-
-
1. Java8新特性_简介
HashMap在jdk1.7和jdk1.8中区别
jdk1.7:数组+链表
jdk1.8:数组+链表+红黑树
当哈希碰撞即链表上个数大于8并且总容量个数大于64,链表转成红黑树
红黑树除了添加以外,其他(查询、删除)效率都比链表高
扩容后重排序,不用重新运算hashCode值,直接找对应元素在原来哈希表的总长度加上它当前所在哈希表的位置
HashSet,同理
ConcurrentHashMap
jdk1.7
并发级别:16
锁+段机制:默认16段,每段默认16表
段太多浪费空间,段太少导致每段元素过多效率遍地
jdk1.8
CAS
无锁算法
CAS是底层操作系统支持的算法,效率高
Java 8新特性简介
- 速度更快
- 代码更少(增加了新的语法Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常 Optional
2. 为什么使用 Lambda 表达式
1-Lambda表达式
为什么使用 Lambda 表达式
Lambda是一个
匿名函数
,我们可以把 Lambda表达式理解为是
一段可以传递的代码
(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
package day01.com.lm.java8;
import java.util.Objects;
public class Employee {
private int id;
private String name;
private Integer age;
private double salary;
private Status status;
public Employee(String name, Integer age, double salary, Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
public Employee() {
super();
}
public Employee(int id) {
this.id = id;
}
public Employee(String name, Integer age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", status=" + status +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return id == employee.id &&
age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age, salary);
}
public enum Status {
FREE,
BUSY,
VOCATION
}
}
package day01.com.lm.java8;
public interface MyPredicate<T> {
public boolean test(T t);
}
package day01.com.lm.java8;
public class FilterEmployeeByAge implements MyPredicate<Employee> {
@Override
public boolean test(Employee t) {
return t.getAge() >= 35;
}
}
package day01.com.lm.java8;
public class FilterEmployeeBySalary implements MyPredicate<Employee> {
@Override
public boolean test(Employee t) {
return t.getSalary() >= 5000;
}
}
package day01.com.lm.java8;
import org.junit.Test;
import java.util.*;
public class TestLambda1 {
//原来的匿名内部类
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(com);
}
//Lambda 表达式
public void test2() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
TreeSet<Integer> ts = new TreeSet<>(com);
}
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99),
new Employee("李四", 38, 5555.99),
new Employee("王五", 50, 6666.66),
new Employee("赵六", 16, 3333.33),
new Employee("田七", 8, 7777.77)
);
//需求:获取当前公司中员工年龄大于35的员工信息
@Test
public void test3() {
List<Employee> list = filterEmployees(this.employees);
for (Employee employee : list) {
System.out.println(employee);
}
}
public List<Employee> filterEmployees(List<Employee> list) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : list) {
if (emp.getAge() >= 35) {
emps.add(emp);
}
}
return emps;
}
//需求:获取当前公司中员工工资大于5000的员工信息
public List<Employee> filterEmployees2(List<Employee> list) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : list) {
if (emp.getSalary() >= 5000) {
emps.add(emp);
}
}
return emps;
}
//优化方式一:策略设计模式
@Test
public void test4() {
List<Employee> list = filterEmployee(employees, new FilterEmployeeByAge());
for (Employee employee : list) {
System.out.println(employee);
}
System.out.println("-----------------------------------");
List<Employee> list2 = filterEmployee(employees, new FilterEmployeeBySalary());
for (Employee employee : list2) {
System.out.println(employee);
}
}
public List<Employee> filterEmployee(List<Employee> list, MyPredicate<Employee> mp) {
List<Employee> emps = new ArrayList<>();
for (Employee employee : list) {
if (mp.test(employee)) {
emps.add(employee);
}
}
return emps;
}
//优化方式二:匿名内部类
@Test
public void test5() {
List<Employee> list = filterEmployee(employees, new MyPredicate<Employee>() {
@Override
public boolean test(Employee t) {
return t.getSalary() <= 5000;
}
});
for (Employee employee : list) {
System.out.println(employee);
}
}
//优化方式三:Lambda表达式
@Test
public void test6() {
List<Employee> list = filterEmployee(employees, (e) -> e.getSalary() <= 5000);
list.forEach(System.out::println);
}
//优化方式四:Stream API
@Test
public void test7() {
employees.stream()
.filter((e) -> e.getSalary() >= 5000)
.limit(2)
.forEach(System.out::println);
System.out.println("----------------------------------------");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
}
3. Java8新特性_Lambda 基础语法
从匿名类到 Lambda 的转换
从原来使用匿名内部类作为参数传递到Lambda表达式作为参数传递
Lambda 表达式语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “
->
” , 该操作符被称
为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
类型推断
上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”
2-函数式接口
什么是函数式接口
-
只包含一个抽象方法的接口,称为
函数式接口
。 - 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
-
我们可以在任意函数式接口上使用
@FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
自定义函数式接口
package day01.com.lm.java8;
import org.junit.Test;
import java.util.*;
import java.util.function.Consumer;
/**
* 一、Lambda表达式的基础语法:Java8中引入了一个新的操作符“->” 该操作符称为箭头操作符或Lambda操作符
* 箭头操作符将Lambda表达式拆分成两部分:
* 左侧:Lambda表达式的参数列表
* 右侧:Lambda表达式中所需要执行的功能,即Lambda体
*
* 语法格式一:无参数,无返回值
* () -> System.out.println("Hello Lambda!");
*
* 语法格式二:有一个参数,并且无返回值
* (x) -> System.out.println(x);
*
* 语法格式三:只有一个参数,小括号可以省略不写
* x -> System.out.println(x);
*
* 语法格式四:有两个以上的参数,有返回值,并且Lambda体有多条语句
* Comparator<Integer> com = (x, y) -> {
* System.out.println("函数式接口");
* return Integer.compare(x, y);
* };
*
* 语法格式五:若Lambda体中只有一条语句,return和大括号都可以省略不写
* Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
*
* 语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即“类型推断”
* Comparator<Integer> com = (Integer x, Integer y) -> Integer.compare(x, y);
*
* 上联:左右遇一括号省
* 下联:左侧推断类型省
* 横批:能省则省
*
* 二、Lambda表达式需要“函数式接口”的支持
* 函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。
* 可以使用注解@FunctionalInterface修饰可以检查是否是函数式接口
*/
public class TestLambda2 {
@Test
public void test1() {//无参数,无返回值
int num = 0;//jdk1.7前,必须加final
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!" + num);
}
};
r.run();
System.out.println("--------------------------------------------");
Runnable r1 = () -> System.out.println("Hello World!" + num);
r1.run();
}
@Test
public void test2() {//有一个参数,并且无返回值
Consumer<String> con = (x) -> System.out.println(x);
con.accept("民哥威武!");
//只有一个参数,小括号可以省略不写
Consumer<String> con2 = x -> System.out.println(x);
con2.accept("民哥威武!");
}
@Test
public void test3() {//有两个以上的参数,有返回值,并且Lambda体有多条语句
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
}
@Test
public void test4() {//若Lambda体中只有一条语句,return和大括号都可以省略不写
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com2 = (Integer x, Integer y) -> Integer.compare(x, y);
}
@Test
public void test5() {
String[] strs = {"aaa", "bbb", "ccc"};
// String[] strs;
// strs = {"aaa", "bbb", "ccc"};
List<String> list = new ArrayList<>();
show(new HashMap<>());
}
public void show(Map<String, Integer> map) {
}
//需求:对一个数进行运算
@Test
public void test6() {
Integer num = operation(100, (x) -> x * x);
System.out.println(num);
System.out.println(operation(200, (y) -> y + 200));
}
public Integer operation(Integer num, MyFun mf) {
return mf.getValue(num);
}
}
package day01.com.lm.java8;
@FunctionalInterface
public interface MyFun<T> {
public Integer getValue(Integer num);
}
4. Java8新特性_Lambda 练习
作为参数传递Lambda表达式
作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接收 Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型。
1.调用 Collections.sort() 方法,通过定制排序比较两个 Employee(先按年龄比,年龄相同按姓名比),使用 Lambda 作为参数传递。
2.
① 声明函数式接口,接口中声明抽象方法, public String getvalue(String str);
② 声明类 Testlambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值。
③ 再将一个字符串的第2个和第4个索引位置进行截取子串。
3.
① 声明一个带两个泛型的函数式接口,泛型类型为<T, R> T为参数,R为返回值
② 接口中声明对应抽象方法
③ 在 TestLambda类中声明方法,使用接口作为参数,计算两个 long 型参数的和。
④ 再计算两个 |ong 型参数的乘积。
package day01.com.lm.exer;
@FunctionalInterface
public interface MyFunction {
public String getValue(String str);
}
package day01.com.lm.exer;
@FunctionalInterface
public interface MyFunction2<T, R> {
public R getValue(T t1, T t2);
}
package day01.com.lm.exer;
import day01.com.lm.java8.Employee;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class TestLambda {
List<Employee> emps = Arrays.asList(
new Employee("张三", 18, 9999.99),
new Employee("李四", 38, 5555.99),
new Employee("王五", 50, 6666.66),
new Employee("赵六", 16, 3333.33),
new Employee("田七", 8, 7777.77)
);
@Test
public void test1() {
Collections.sort(emps, (e1, e2) -> {
if(e1.getAge() == e2.getAge()) {
return e1.getName().compareTo(e2.getName());
} else {
return -Integer.compare(e1.getAge(), e2.getAge());
}
});
for (Employee emp : emps) {
System.out.println(emp);
}
}
//需求:用于处理字符串
public String strHandler(String str, MyFunction mf) {
return mf.getValue(str);
}
@Test
public void test2() {
String trimStr = strHandler("\t\t I Love China! \t ", str -> str.trim());
System.out.println(trimStr);
String upperStr = strHandler("I Love China!", str -> str.toUpperCase());
System.out.println(upperStr);
String substringStr = strHandler("I Love China!", str -> str.substring(2, 6));
System.out.println(substringStr);
}
//需求:对于两个Long型数据进行处理
public Long longHandler(Long l1, Long l2, MyFunction2<Long, Long> mf) {
return mf.getValue(l1, l2);
}
@Test
public void test3() {
Long addLong = longHandler(100L, 200L, (l1, l2) -> l1 + l2);
System.out.println(addLong);
Long minusLong = longHandler(100L, 200L, (l1, l2) -> l1 * l2);
System.out.println(minusLong);
}
}
5. Java8新特性_四大内置核心函数式接口
Java 内置四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer<T> 消费型接口 |
T | void |
对类型为T的对象应用操作,包含方法:
|
Supplier<T> 供给型接口 |
无 | T |
返回类型为T的对象,包含方法:
|
Function<T, R> 函数型接口 |
T | R |
对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:
|
Predicate<T> 断定型接口 |
T | boolean |
确定类型为T的对象是否满足某约束,并返回 boolean 值。包含方法:
|
其他接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction<T, U, R> |
T, U | R |
对类型为T,U参数应用操作,返回R类型的结果。包含方法为:
|
UnaryOperator<T> (Function子接口) |
T | T |
对类型为T的对象进行一元运算,并返回T类型的结果,包含方法为:
|
BinaryOperator<T> (BiFunction子接口) |
T, T | T |
对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为:
|
BiConsumer<T, U> | T, U | void |
对类型为T,U参数应用操作。包含方法为:
|
ToIntFunction<T> ToLongFunction<T> ToDoubleFunction<T> |
T |
int long double |
分别计算int、long、double值的函数 |
IntFunction<R> LongFunction<R> DoubleFunction<R> |
int long double |
R | 参数分别为int、long、double类型的函数 |
package day01.com.lm.java8;
import org.junit.Test;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Java内置的四大核心函数式接口
*
* Consumer<T>:消费型接口
* void accept(T t);
*
* Supplier<T>:供给型接口
* T get();
*
* Function<T, R>:函数型接口
* R apply(T t);
*
* Predicate<T>:断言型接口
* boolean test(T t);
*/
public class TestLambda3 {
//Consumer<T> 消费型接口:
@Test
public void test1() {
happy(10000, (m) -> System.out.println("民哥喜欢大宝剑,每次消费" + m + "元"));
}
public void happy(double money, Consumer<Double> con) {
con.accept(money);
}
//Supper<T> 供给型接口:
@Test
public void test2() {
List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
for (Integer num : numList) {
System.out.println(num);
}
}
//需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = sup.get();
list.add(n);
}
return list;
}
//Function<T, R> 函数型接口:
@Test
public void test3() {
String newStr = strHandler("\t\t I Love China! \t", (str) -> str.trim());
System.out.println(newStr);
String subStr = strHandler("I Love China!", (str) -> str.substring(2, 6));
System.out.println(subStr);
}
//需求:用于处理字符串
public String strHandler(String str, Function<String, String> fun) {
return fun.apply(str);
}
//Predicate<T> 断言型接口:
@Test
public void test4() {
List<String> list = Arrays.asList("Hello", "I", "Love", "China");
List<String> strList = filterStr(list, (s) -> s.length() > 4);
for (String str : strList) {
System.out.println(str);
}
}
//需求:将满足条件的字符串放入集合中去
public List<String> filterStr(List<String> list, Predicate<String> pre) {
List<String> strList = new ArrayList<>();
for (String str : list) {
if (pre.test(str)) {
strList.add(str);
}
}
return strList;
}
}
6. Java8新特性_方法引用与构造器引用
3-方法引用与构造器引用
方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
(
实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!
)
方法引用:使用操作符 “
::
” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况:
-
对象::实例方法
-
类::静态方法
-
类::实例方法
注意
:当需要引用方法的第一个参数是调用对象,并且第二个参数是需要引用方法的第二个参数(或无参数)时:ClassName::methodName
构造器引用
格式:
ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。
可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致!
数组引用
格式:
type[] :: new
package day01.com.lm.java8;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.*;
/**
* 一、方法引用:若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”
* (可以理解方法引用是Lambda表达式的另外一种表现形式)
*
* 主要有三种语法格式:
*
* 对象::实例方法名
*
* 类::静态方法名
*
* 类::实例方法名
*
* 注意:
* ①Lambda体中调用方法的参数和返回值类型,要与函数式接口中抽象方法的函数列表和返回值保持一致!
* ②若Lambda参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName :: method
*
* 二、构造器引用:
*
* 格式:
*
* ClassName::new
*
* 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表一致
*
* 三、数组引用
*
* Type::new
*/
public class TestMethodRef {
//对象::实例方法名
@Test
public void test1() {
String abcdef = "abcdef";
PrintStream ps1 = System.out;
Consumer<String> con = (x) -> ps1.println(x);
con.accept(abcdef);
PrintStream ps = System.out;
Consumer<String> con1 = ps::println;
con1.accept(abcdef);
Consumer<String> con2 = System.out::println;
con2.accept(abcdef);
}
@Test
public void test2() {
Employee emp = new Employee();
Supplier<String> sup = () -> emp.getName();
String str = sup.get();
System.out.println(str);
Supplier<Integer> sup2 = emp::getAge;
Integer num = sup2.get();
System.out.println(num);
}
//类::静态方法名
@Test
public void test3() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
System.out.println(com.compare(6, 7));
Comparator<Integer> com1 = Integer::compare;
System.out.println(com1.compare(6, 7));
}
//类::实例方法名
@Test
public void test4() {
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("abc", "abc"));
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("abc", "abc"));
System.out.println(bp2.test("abc", null));
// System.out.println(bp2.test(null, "abc"));//空指针异常
}
//构造器引用
@Test
public void test5() {
Supplier<Employee> sup = () -> new Employee();
//构造器引用方式
Supplier<Employee> sup2 = Employee::new;
Employee emp = sup2.get();
System.out.println(emp);
}
@Test
public void test6() {
Function<Integer, Employee> fun = (x) -> new Employee(x);
Function<Integer, Employee> fun2 = Employee::new;
Employee emp = fun2.apply(101);
System.out.println(emp);
// BiFunction<Integer, Integer, Employee> bf = Employee::new;//Employee没有传2个参数的构造器,所以不可引用
}
//数组引用
@Test
public void test7() {
Function<Integer, String[]> fun = (x) -> new String[x];
String[] strs = fun.apply(10);
System.out.println(strs.length);
Function<Integer, String[]> fun2 = String[]::new;
String[] strs2 = fun2.apply(20);
System.out.println(strs2.length);
}
}
7. Java8新特性_创建 Stream
4-强大的 Stream API
了解 Stream
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是
Stream API(java.util.stream.*)
。
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
什么是 Stream
流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意:
① Stream 自己不会存储元素。
② Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③ Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream 的操作三个步骤
-
创建 Stream
一个数据源(如:集合、数组),获取一个流 -
中间操作
一个中间操作链,对数据源的数据进行处理 -
终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果
创建 Stream
-
从Collection 获取流
Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream<E> stream()
: 返回一个顺序流
default Stream<E> parallelStream()
: 返回一个并行流 -
由数组创建流
Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static <T> Stream<T> stream(T[] array)
: 返回一个流
重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
-
由值创建流
可以使用静态方法 Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数。
public static<T> Stream<T> of(T... values)
: 返回一个流 -
由函数创建流:创建无限流
可以使用静态方法 Stream.iterate() 和 Stream.generate(), 创建无限流。-
迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
-
生成
public static<T> Stream<T> generate(Supplier<T> s)
-
迭代
package day02.com.lm.java8;
import java.util.Objects;
public class Employee {
private int id;
private String name;
private Integer age;
private double salary;
private Status status;
public Employee(String name, Integer age, double salary, Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
public Employee() {
super();
}
public Employee(int id) {
this.id = id;
}
public Employee(String name, Integer age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(int id, String name, Integer age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", status=" + status +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return id == employee.id &&
age == employee.age &&
Double.compare(employee.salary, salary) == 0 &&
Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age, salary);
}
public enum Status {
FREE,
BUSY,
VOCATION
}
}
package day02.com.lm.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤
*
* 1、创建Stream
*
* 2、中间操作
*
* 3、终止操作(终端操作)
*/
public class TestStreamAPI1 {
//创建 Stream
@Test
public void test1() {
//1、可以通过 Collection 系列集合提供的 stream() 或 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//2、通过 Arrays 中的静态方法 stream() 获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
//3、通过 Stream 类中的静态方法 of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
//4、创建无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
}
}
8. Java8新特性_Stream_筛选与切片
9. Java8新特性_Stream_映射
10. Java8新特性_Stream_排序
Stream 的中间操作
多个
中间操作
可以连接起来形成一个
流水线
,除非流水线上触发终止操作,否则
中间操作不会执行任何的处理
!而在
终止操作时一次性全部处理,称为“惰性求值”
。
-
筛选与切片
方 法 | 描 述 |
---|---|
filter(Predicate p) | 接收 Lambda ,从流中排除某些元素。 |
distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |
-
映射
方 法 | 描 述 |
---|---|
map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 |
mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 |
mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 |
mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 |
flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |
-
排序
方 法 | 描 述 |
---|---|
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
package day02.com.lm.java8;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
/**
* 一、Stream的三个操作步骤
*
* 1、创建Stream
*
* 2、中间操作
*
* 3、终止操作(终端操作)
*/
public class TestStreamAPI2 {
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99),
new Employee("李四", 38, 5555.99),
new Employee("王五", 50, 6666.66),
new Employee("赵六", 16, 3333.33),
new Employee("田七", 12, 8888.88),
new Employee("田七", 12, 8888.88),
new Employee("田七", 12, 8888.88)
);
//中间操作
/**
筛选与切片
filter——接收 Lambda ,从流中排除某些元素。
limit——截断流,使其元素不超过给定数量。
skip(n)——跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 (注意:需重写hashCode() 和 equals())
*/
//内部迭代:迭代操作由 Stream API 完成
@Test
public void test1() {
//中间操作:不会执行任何操作
Stream<Employee> stream = employees.stream()
.filter((e) -> {
System.out.println("Stream API 的中间操作");//可以看出,如果没有终止操作,中间操作不会执行
return e.getAge() > 35;
});
//终止操作:一次性执行全部内容,即“惰性求值”
stream.forEach(System.out::println);
}
//外部迭代
@Test
public void test2() {
Iterator<Employee> it = employees.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
@Test
public void test3() {
employees.stream()
.filter((e) -> {
System.out.println("短路");
return e.getSalary() > 5000;
})
.limit(2)
.forEach(System.out::println);
}
@Test
public void test4() {
employees.stream()
.filter((e) -> e.getSalary() > 5000)
.skip(2)
.distinct()
.forEach(System.out::println);
}
/**
映射
map——接收 Lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap——接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
*/
@Test
public void test5() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("---------------------------------");
employees.stream()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("---------------------------------");
Stream<Stream<Character>> stream = list.stream()
.map(TestStreamAPI2::filterCharacter);
stream.forEach(sm -> {
sm.forEach(System.out::println);
});
System.out.println("---------------------------------");
Stream<Character> sm = list.stream()
.flatMap(TestStreamAPI2::filterCharacter);
sm.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str) {
ArrayList<Character> list = new ArrayList<>();
for (Character c: str.toCharArray()) {
list.add(c);
}
return list.stream();
}
@Test
public void test6() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
List list2 = new ArrayList();
list2.add(11);
list2.add(22);
list2.add(list);
System.out.println(list2);
List list3 = new ArrayList();
list3.add(11);
list3.add(22);
list3.addAll(list);
System.out.println(list3);
}
/**
排序
sorted()——自然排序(Comparable)
sorted(Comparator com)——定制排序(Comparator)
*/
@Test
public void test7() {
List<String> list = Arrays.asList("ccc", "aaa", "bbb", "ddd", "eee");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("---------------------------------");
employees.stream()
.sorted((e1, e2) -> {
if (e1.getAge().equals(e2.getAge())) {
return e1.getName().compareTo(e2.getName());
} else {
return e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
}
}
11. Java8新特性_Stream_查找与匹配
Stream 的终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
-
查找与匹配
方 法 | 描 述 |
---|---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) |
内部迭代 (使用 Collection 接口需要用户去做迭代,称为 外部迭代 。 相反,Stream API 使用内部迭代——它帮你把迭代做了) |
12. Java8新特性_Stream_归约与收集
-
归约
方 法 | 描 述 |
---|---|
reduce(T iden, BinaryOperator b) |
可以将流中元素反复结合起来,得到一个值。 返回 T |
reduce(BinaryOperator b) |
可以将流中元素反复结合起来,得到一个值。 返回 Optional<T> |
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。
-
收集
方 法 | 描 述 |
---|---|
collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
方法 | 返回类型 | 作用 |
---|---|---|
toList | List<T> |
把流中元素收集到List List<Employee> emps = list.stream().collect(Collectors.toList()); |
toSet | Set<T> |
把流中元素收集到Set Set<Employee> emps = list.stream().collect(Collectors.toSet()); |
toCollection | Collection<T> |
把流中元素收集到创建的集合 Collection<Employee> emps = list.stream().collect(Collectors.toCollection(ArrayList::new)); |
counting | Long |
计算流中元素的个数 long count = list.stream().collect(Collectors.counting()); |
summingInt | Integer |
对流中元素的整数属性求和 int total = list.stream().collect(Collectors.summingInt(Employee::getSalary)); |
averagingInt | Double |
计算流中元素Integer属性的平均值 double avg = list.stream().collect(Collectors.averagingInt(Employee::getSalary)); |
summarizingInt | IntSummaryStatistics |
收集流中Integer属性的统计值。 如:平均值 IntSummaryStatistics iss = list.stream().collect(Collectors.summarizingInt(Employee::getSalary)); |
joining | String |
连接流中每个字符串 String str = list.stream().map(Employee::getName).collect(Collectors.joining()); |
maxBy | Optional<T> |
根据比较器选择最大值 Optional<Emp> max = list.stream().collect(Collectors.maxBy(comparingInt(Employee::getSalary))); |
minBy | Optional<T> |
根据比较器选择最小值 Optional<Emp> min = list.stream().collect(Collectors.minBy(comparingInt(Employee::getSalary))); |
reducing | 归约产生的类型 |
从一个作为累加器的初始值开始,利用BinaryOperator与流中元素逐个结合,从而归约成单个值 int total = list.stream().collect(Collectors.reducing(0, Employee::getSalar, Integer::sum)); |
collectingAndThen | 转换函数返回的类型 |
包裹另一个收集器,对其结果转换函数 int how = list.stream().collect(Collectors.collectingAndThen(Collectors.toList(), List::size)); |
groupingBy | Map<K, List<T>> |
根据某属性值对流分组,属性为K,结果为V Map<Emp.Status, List<Emp>> map = list.stream().collect(Collectors.groupingBy(Employee::getStatus)); |
partitioningBy | Map<Boolean, List<T>> |
根据true或false进行分区 Map<Boolean, List<Emp>> vd = list.stream().collect(Collectors.partitioningBy(Employee::getManage)); |
package day02.com.lm.java8;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import day02.com.lm.java8.Employee.Status;
public class TestStreamAPI3 {
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99, Status.FREE),
new Employee("李四", 58, 5555.55, Status.BUSY),
new Employee("王五", 26, 3333.33, Status.VOCATION),
new Employee("赵六", 36, 6666.66, Status.FREE),
new Employee("田七", 12, 8888.88, Status.BUSY),
new Employee("田七", 12, 8888.88, Status.BUSY)
);
/*
查找与匹配
allMatch——检查是否匹配所有元素
anyMatch——检查是否至少匹配一个元素
noneMatch——检查是否没有匹配所有元素
findFirst——返回第一个元素
findAny——返回当前流中的任意元素
count——返回流中元素的总个数
max——返回流中最大值
min——返回流中最小值
*/
@Test
public void test1() {
boolean b1 = employees.stream()
.allMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(b1);
boolean b2 = employees.stream()
.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(b2);
boolean b3 = employees.stream()
.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(b3);
Optional<Employee> op = employees.stream()
.sorted((e1, e2) -> -Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
Optional<Employee> op2 = employees.stream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op.get());
Optional<Employee> op3 = employees.parallelStream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op3.get());
}
@Test
public void test2() {
Long count = employees.stream()
.count();
System.out.println(count);
Optional<Employee> op1 = employees.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op1.get());
Optional<Double> op2 = employees.stream()
.map(Employee::getSalary)
.min(Double::compareTo);
System.out.println(op2.get());
}
/*
规约
reduce(T identity, BinaryOperator) / reduce(BinaryOperator)——可以将流中元素反复结合起来,得到一个值
*/
@Test
public void test3() {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("-------------------------------");
Optional<Double> op = employees.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
/*
收集
collect——将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
*/
@Test
public void test4() {
List<String> list = employees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
System.out.println("-------------------------------");
Set<String> set = employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("-------------------------------");
HashSet<String> hashSet = employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);
}
@Test
public void test5() {
//总数
Long count = employees.stream()
.collect(Collectors.counting());
System.out.println(count);
System.out.println("-------------------------------");
//平均值
Double avg = employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
//总和
Double sum = employees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值
Optional<Employee> max = employees.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值
Optional<Double> min = employees.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
//分组
@Test
public void test6() {
Map<Status, List<Employee>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
//多级分组
@Test
public void test7() {
Map<Status, Map<String, List<Employee>>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (((Employee) e).getAge() <= 35) {
return "青年";
} else if (((Employee) e).getAge() <= 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(map);
}
//分片
@Test
public void test8() {
Map<Boolean, List<Employee>> map = employees.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000.00));
System.out.println(map);
}
@Test
public void test9() {
DoubleSummaryStatistics dss = employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getSum());
System.out.println(dss.getAverage());
System.out.println(dss.getMax());
}
@Test
public void test10() {
String str = employees.stream()
.map(Employee::getName)
.collect(Collectors.joining(",", "【", "】"));
System.out.println(str);
}
}
13. Java8新特性_Stream API 练习
package day02.com.lm.exer;
import day01.com.lm.java8.Employee;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class TestStreamAPI {
List<Employee> employees = Arrays.asList(
new Employee("张三", 18, 9999.99, Employee.Status.FREE),
new Employee("李四", 58, 5555.55, Employee.Status.BUSY),
new Employee("王五", 26, 3333.33, Employee.Status.VOCATION),
new Employee("赵六", 36, 6666.66, Employee.Status.FREE),
new Employee("田七", 12, 8888.88, Employee.Status.BUSY),
new Employee("田七", 12, 8888.88, Employee.Status.BUSY)
);
/*
1.给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?
,给定【1,2,3,4,5】,应该返回【1,4,9,16,25】。
*/
@Test
public void test1() {
Integer[] nums = new Integer[]{1, 2, 3, 4, 5};
Arrays.stream(nums)
.map((x) -> x * x)
.forEach(System.out::println);
}
/*
2.怎样用map和 reduce方法数一数流中有多少个Emp1oyee呢?
*/
@Test
public void test2() {
Optional<Integer> op = employees.stream()
.map((e) -> 1)
.reduce(Integer::sum);
System.out.println(op.get());
}
}
package day02.com.lm.exer;
/**
* 交易员类
*/
public class Trader {
private String name;
private String city;
public Trader() {
}
public Trader(String name, String city) {
this.name = name;
this.city = city;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
@Override
public String toString() {
return "Trader{" +
"name='" + name + '\'' +
", city='" + city + '\'' +
'}';
}
}
package day02.com.lm.exer;
/**
* 交易类
*/
public class Transaction {
private Trader trader;
private int year;
private int value;
public Transaction() {
}
public Transaction(Trader trader, int year, int value) {
this.trader = trader;
this.year = year;
this.value = value;
}
public Trader getTrader() {
return trader;
}
public void setTrader(Trader trader) {
this.trader = trader;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
@Override
public String toString() {
return "Transaction{" +
"trader=" + trader +
", year=" + year +
", value=" + value +
'}';
}
}
package day02.com.lm.exer;
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TestTransaction {
List<Transaction> transactions = null;
@Before
public void before() {
Trader raoul = new Trader( "Raoul","Cambridge");
Trader mario = new Trader("Mario","Milan");
Trader alan = new Trader ("Alan","Cambridge");
Trader brian = new Trader("Brian","Cambridge");
transactions = Arrays.asList(
new Transaction(brian, 2011, 300),
new Transaction(raoul, 2012, 1000),
new Transaction (raoul, 2011, 400),
new Transaction (mario, 2012, 710),
new Transaction(mario, 2012, 700),
new Transaction(alan, 2012, 950)
);
}
// 1.找出2011年发生的所有交易,并按交易额排序(从低到高)
@Test
public void test1() {
transactions.stream()
.filter((t) -> t.getYear() == 2011)
.sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()))
.forEach(System.out::println);
}
// 2.交易员都在哪些不同的城市工作过?
@Test
public void test2() {
transactions.stream()
.map((t) -> t.getTrader().getCity())
.distinct()
.forEach(System.out::println);
}
// 3.查找所有来自剑桥的交易员,并按姓名排序。
@Test
public void test3() {
transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getTrader)
.distinct()
.sorted((t1, t2) -> t1.getName().compareTo(t2.getName()))
.forEach(System.out::println);
}
// 4.返回所有交易员的姓名字符串,按字母顺序排序
@Test
public void test4() {
transactions.stream()
.map((t) -> t.getTrader().getName())
.distinct()
.sorted()
.forEach(System.out::println);
System.out.println("-----------------------------------------");
String str = transactions.stream()
.map((t) -> t.getTrader().getName())
.distinct()
.sorted()
.reduce("", String::concat);
System.out.println(str);
System.out.println("-----------------------------------------");
transactions.stream()
.map((t) -> t.getTrader().getName())
.distinct()
.flatMap(this::filterCharater)
.sorted((s1, s2) -> s1.compareToIgnoreCase(s2))
.forEach(System.out::print);
}
private Stream<String> filterCharater(String str) {
List<String> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c.toString());
}
return list.stream();
}
// 5.有没有交易员是在米兰工作的?
@Test
public void test5() {
boolean bl = transactions.stream()
.anyMatch((t) -> t.getTrader().getCity().equals("Milan"));
System.out.println(bl);
}
// 6.打印生活在剑桥的交易员的所有交易额
@Test
public void test6() {
Optional<Integer> sum = transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);
System.out.println(sum.get());
}
// 7.所有交易中,最高的交易额是多少
@Test
public void test7() {
Optional<Integer> max = transactions.stream()
.map((t) -> t.getValue())
.max(Integer::compare);
System.out.println(max.get());
}
// 8.找到交易额最小的交易
@Test
public void test8() {
Optional<Transaction> min = transactions.stream()
.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
System.out.println(min.get());
}
}
14. Java8新特性_并行流与串行流
传统线程存在的问题:某些线程可能阻塞繁忙,某些线程可能顺畅清闲,从而导致线程使用效率低下。
并行流与串行流
并行流
就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。
Fork/Join 框架
Fork/Join 框架
:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。
Fork/Join 框架与传统线程池的区别
采用 “工作窃取”模式(work-stealing):
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上。在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。
而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行。那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行。这种方式减少了线程的等待时间,提高了性能。
package day02.com.lm.java8;
import java.util.concurrent.RecursiveTask;
public class ForkJoinCalculate extends RecursiveTask<Long> {
private long start;
private long end;
private static final long THRESHOLD = 10000;
public ForkJoinCalculate(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start;
if (length <= THRESHOLD) {
long sum = 0;
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long middle = (start + end) / 2;
ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
left.fork();// 拆分子任务,同时压入线程队列
ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
right.fork();
return left.join() + right.join();
}
}
}
package day02.com.lm.java8;
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.stream.LongStream;
public class TestForkJoin {
/**
* ForkJoin 框架
*/
@Test
public void test1() {
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(0, 100000000000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗费时间:"+Duration.between(start, end).toMillis());//15999
}
/**
* 普通 for
*/
@Test
public void test2() {
Instant start = Instant.now();
long sum = 0L;
for (long i = 0; i <= 100000000000L; i++) {
sum += i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗费时间:"+Duration.between(start, end).toMillis());//28264
}
/**
* java8 并行流
*/
@Test
public void test3() {
Instant start = Instant.now();
LongStream.rangeClosed(0, 100000000000L)
.parallel()
.reduce(0, Long::sum);
Instant end = Instant.now();
System.out.println("耗费时间:"+Duration.between(start, end).toMillis());//11216
}
}
15. Java8新特性_Optional 容器类
Optional 容器类的常用方法:
方法 | 说明 |
---|---|
Optional.of(T t) | 创建一个 Optional实例 |
Optional.empty() | 创建一个空的 Optional实例 |
Optional.ofNullable(T t) | 若t不为null,创建 Optional实例,否则创建空实例 |
isPresent() | 判断是否包含值 |
orElse(T t) | 如果调用对象包含值,返回该值,否则返回t |
orElseGet(Supplier s) | 如果调用对象包含值,返回该值,否则返回s获取的值 |
map(Function f) | 如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty() |
flatMap(Function mapper) | 与map类似,要求返回值必须是 Optional |
package day02.com.lm.java8;
import org.junit.Test;
import java.util.Optional;
public class TestOptional {
/*
Optional 容器类的常用方法:
Optional.of(T t):创建一个 Optiona1实例
Optional.empty():创建一个空的 Optiona1实例
Optional.ofNu1lable(T t):若t不为nu11,创建 Optional实例,否则创建空实例
isPresent():判断是否包含值
orElse(T t):如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f):如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.empty()
f1atMap(Function mapper):与map类似,要求返回值必须是 Optional
*/
@Test
public void test1() {
Optional<Employee> op = Optional.of(null); //java.lang.NullPointerException
Employee emp = op.get();
System.out.println(emp);
}
@Test
public void test2() {
Optional<Object> op = Optional.empty();
System.out.println(op.get()); //java.util.NoSuchElementException: No value present
}
@Test
public void test3() {
Optional<Employee> op = Optional.ofNullable(null);
System.out.println(op.get()); //java.util.NoSuchElementException: No value present
Optional<Object> op1 = Optional.ofNullable(null);
if (op1.isPresent()) { //false
System.out.println(op1.get());
}
Optional<Employee> op2 = Optional.ofNullable(new Employee());
if (op2.isPresent()) { //true
System.out.println(op2.get());
}
Optional<Employee> op3 = Optional.ofNullable(new Employee());
Employee emp3 = op3.orElse(new Employee("张三", 22, 8888));
System.out.println(emp3); //Employee{id=0, name='null', age=null, salary=0.0, status=null}
Optional<Employee> op4 = Optional.ofNullable(null);
Employee emp4 = op4.orElse(new Employee("张三", 22, 8888));
System.out.println(emp4); //Employee{id=0, name='张三', age=22, salary=8888.0, status=null}
Optional<Employee> op5 = Optional.ofNullable(null);
Employee emp5 = op5.orElseGet(() -> new Employee());
System.out.println(emp5); //Employee{id=0, name='null', age=null, salary=0.0, status=null}
}
@Test
public void test4() {
Optional<Employee> op = Optional.ofNullable(new Employee("张三", 22, 8888));
Optional<String> opStr = op.map((e) -> e.getName());
System.out.println(opStr.get()); //张三
Optional<String> opStr2 = op.flatMap((e) -> Optional.of(e.getName()));
System.out.println(opStr2.get()); //张三
}
// 需求:获取一个男人心中女神的名字
public String getGodnessName(Man man) {
if (man != null) {
Godness gn = man.getGodness();
if (gn != null) {
return gn.getName();
}
}
return "小红";
}
// 例题
@Test
public void test5() {
Man man = new Man();
String n = getGodnessName(man);
System.out.println(n);//小红
Optional<NewMan> op = Optional.ofNullable(null);
String str = getGodnessName2(op);
System.out.println(str);//小花
op = Optional.ofNullable(new NewMan());
str = getGodnessName2(op);
System.out.println(str);//小花
Optional<Godness> gn = Optional.ofNullable(new Godness("小芳"));
op = Optional.ofNullable(new NewMan(gn));
str = getGodnessName2(op);
System.out.println(str);//小芳
}
public String getGodnessName2(Optional<NewMan> man) {
return man.orElse(new NewMan())
.getGodness().orElse(new Godness("小花"))
.getName();
}
}
package day02.com.lm.java8;
public class Man {
private Godness godness;
public Man() {
}
public Man(Godness godness) {
this.godness = godness;
}
public Godness getGodness() {
return godness;
}
public void setGodness(Godness godness) {
this.godness = godness;
}
@Override
public String toString() {
return "Man{" +
"godness=" + godness +
'}';
}
}
package day02.com.lm.java8;
public class Godness {
private String name;
public Godness() {
}
public Godness(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Godness{" +
"name='" + name + '\'' +
'}';
}
}
package day02.com.lm.java8;
import java.util.Optional;
public class NewMan {
private Optional<Godness> godness = Optional.empty();
public NewMan() {
}
public NewMan(Optional<Godness> godness) {
this.godness = godness;
}
public Optional<Godness> getGodness() {
return godness;
}
public void setGodness(Optional<Godness> godness) {
this.godness = godness;
}
@Override
public String toString() {
return "NewMan{" +
"godness=" + godness +
'}';
}
}
16. Java8新特性_接口中的默认方法与静态方法
6-接口中的默认方法与静态方法
接口中的默认方法
Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default 关键字修饰。
例如:
接口默认方法的”类优先”原则
若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时
- 选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
-
接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。
接口中的静态方法
Java8 中,接口中允许添加静态方法。
例如:
package day02.com.lm.java8;
public class MyClass {
public String getName() {
return "类嘿嘿嘿";
}
}
package day02.com.lm.java8;
public interface MyFun {
default String getName() {
return "接口哈哈哈";
}
}
package day02.com.lm.java8;
public interface MyInterface {
default String getName() {
return "接口2呵呵呵";
}
public static void show() {
System.out.println("接口中的静态方法");
}
}
package day02.com.lm.java8;
public class SubClass extends MyClass implements MyFun {
}
package day02.com.lm.java8;
public class SubClass2 implements MyFun, MyInterface {
@Override
public String getName() {
// return MyInterface.super.getName();
return MyFun.super.getName();
}
}
package day02.com.lm.java8;
public class TestDefaultInterface {
public static void main(String[] args) {
SubClass sc = new SubClass();
System.out.println(sc.getName());//类嘿嘿嘿
SubClass2 sc2 = new SubClass2();//接口哈哈哈
System.out.println(sc2.getName());
MyInterface.show();//接口中的静态方法
}
}
17. Java8新特性_传统时间格式化的线程安全问题
5-新时间日期 API
使用 LocalDate、LocalTime、LocalDateTime
LocalDate、LocalTime、LocalDateTime 类的实例是
不可变的对象
,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法
方法 | 描述 | 示例 |
---|---|---|
now() | 静态方法,根据当前时间创建对象 |
LocalDate localDate = LocalDate.now(); LocalTime localTime = LocalTime.now(); LocalDateTime localDateTime = LocalDateTime.now(); |
of() | 静态方法,根据指定日期/时间创建对象 |
LocalDate localDate = LocalDate.of(2016, 10, 26); LocalTime localTime = LocalTime.of(02, 22, 56); LocalDateTime localDateTime = LocalDateTime.of(2016, 10, 26, 12, 10, 55); |
plusDays, plusWeeks, plusMonths, plusYears | 向当前 LocalDate 对象添加几天、几周、几个月、几年 | |
minusDays, minusWeeks, minusMonths, minusYears | 从当前 LocalDate 对象减去几天、几周、几个月、几年 | |
plus, minus | 添加或减少一个 Duration 或 Period | |
withDayOfMonth, withDayOfYear, withMonth, withYear | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的LocalDate 对象 | |
getDayOfMonth | 获得月份天数(1-31) | |
getDayOfYear | 获得年份天数(1-366) | |
getDayOfWeek | 获得星期几(返回一个 DayOfWeek 枚举值) | |
getMonth | 获得月份, 返回一个 Month 枚举值 | |
getMonthValue | 获得月份(1-12) | |
getYear | 获得年份 | |
until | 获得两个日期之间的 Period 对象,或者指定 ChronoUnits 的数字 | |
isBefore, isAfter | 比较两个 LocalDate | |
isLeapYear | 判断是否是闰年 |
Instant 时间戳
用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算
Duration 和 Period
- Duration:用于计算两个“时间”间隔
- Period:用于计算两个“日期”间隔
日期的操纵
- TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。
-
TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。
例如获取下个周日:
解析与格式化
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
- 预定义的标准格式
- 语言环境相关的格式
- 自定义的格式
时区的处理
Java8 中加入了对时区的支持,带时区的时间为分别为:
ZonedDate、ZonedTime、ZonedDateTime
其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式
例如 :Asia/Shanghai 等
ZoneId:该类中包含了所有的时区信息
getAvailableZoneIds() : 可以获取所有时区信息
of(id) : 用指定的时区信息获取 ZoneId 对象
与传统日期处理的转换
类 | To 遗留类 | From 遗留类 |
---|---|---|
java.time.Instant java.util.Date |
Date.from(instant) | date.toInstant() |
java.time.Instant java.sql.Timestamp |
Timestamp.from(instant) | timestamp.toInstant() |
java.time.ZonedDateTime java.util.GregorianCalendar |
GregorianCalendar.from(zonedDateTime) | cal.toZonedDateTime() |
java.time.LocalDate java.sql.Time |
Date.valueOf(localDate) | date.toLocalDate() |
java.time.LocalTime java.sql.Time |
Date.valueOf(localDate) | date.toLocalTime() |
java.time.LocalDateTime java.sql.Timestamp |
Timestamp.valueOf(localDateTime) | timestamp.toLocalDateTime() |
java.time.ZoneId java.util.TimeZone |
Timezone.getTimeZone(id) | timeZone.toZoneId() |
java.time.format.DateTimeFormatter java.text.DateFormat |
formatter.toFormat() | 无 |
package day03.com.lm.java8;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestSimpleDateFormat {
public static void main(String[] args) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return sdf.parse("20161218");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(pool.submit(task));
}
for (Future<Date> future : results) {
System.out.println(future.get());
}
pool.shutdown();
}
}
上述代码有线程安全问题,运行会报如下错:
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.NumberFormatException: For input string: ".1122E2.1122E2"
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at day02.com.lm.java8.TestSimpleDateFormat.main(TestSimpleDateFormat.java:35)
Caused by: java.lang.NumberFormatException: For input string: ".1122E2.1122E2"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1867)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at day02.com.lm.java8.TestSimpleDateFormat$1.call(TestSimpleDateFormat.java:21)
at day02.com.lm.java8.TestSimpleDateFormat$1.call(TestSimpleDateFormat.java:18)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
改成用ThreadLocal给DateFormat加上锁:
package day03.com.lm.java8;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date convert(String source) throws ParseException {
return df.get().parse(source);
}
}
package day02.com.lm.java8;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestSimpleDateFormat {
public static void main(String[] args) throws Exception {
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return DateFormatThreadLocal.convert("20161218");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(pool.submit(task));
}
for (Future<Date> future : results) {
System.out.println(future.get());
}
pool.shutdown();
}
}
运行结果正常:
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Sun Dec 18 00:00:00 CST 2016
Java8,全新的日期时间API:
package day03.com.lm.java8;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class TestSimpleDateFormat {
public static void main(String[] args) throws Exception {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20161218", dtf);
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<LocalDate>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(pool.submit(task));
}
for (Future<LocalDate> future : results) {
System.out.println(future.get());
}
pool.shutdown();
}
}
运行结果如下:
2016-12-18
2016-12-18
2016-12-18
2016-12-18
2016-12-18
2016-12-18
2016-12-18
2016-12-18
2016-12-18
2016-12-18
18. Java8新特性_新时间与日期 API-本地时间与时间戳
package day03.com.lm.java8;
import org.junit.Test;
import java.time.*;
public class TestLocalDateTime {
//1. LocalDate LocalTime LocalDateTime
@Test
public void test1() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); // 2021-05-04T15:20:47.034
LocalDateTime ldt2 = LocalDateTime.of(2015, 10, 19, 13, 22, 33);
System.out.println(ldt2); // 2015-10-19T13:22:33
LocalDateTime ldt3 = ldt.plusYears(2);
System.out.println(ldt3); // 2023-05-04T15:20:47.034
LocalDateTime ldt4 = ldt.minusMonths(2);
System.out.println(ldt4); // 2021-03-04T15:20:47.034
System.out.println(ldt.getYear()); // 2021
System.out.println(ldt.getMonthValue()); // 5
System.out.println(ldt.getDayOfMonth()); // 4
System.out.println(ldt.getHour()); // 15
System.out.println(ldt.getMinute()); // 20
System.out.println(ldt.getSecond()); // 47
}
//2. Instant : 时间戳(以 Unix 元年:1970年1月1日 00:00:00 到某个时间之间的毫秒值)
@Test
public void test2() {
Instant ins1 = Instant.now();// 默认获取 UTC 时区
System.out.println(ins1); // 2021-05-04T07:19:47.759Z
OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt); // 2021-05-04T15:19:47.759+08:00
System.out.println(ins1.toEpochMilli()); // 1620112787759
Instant ins2 = Instant.ofEpochSecond(1);
System.out.println(ins2); // 1970-01-01T00:00:01Z
OffsetDateTime odt2 = ins2.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt2); // 1970-01-01T08:00:01+08:00
}
//3.
//Duration : 计算两个“时间”之间的间隔
//Period : 计算两个“日期”之间的间隔
@Test
public void test3() {
Instant ins1 = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant ins2 = Instant.now();
Duration duration = Duration.between(ins1, ins2);
System.out.println(duration); // PT1.01S
System.out.println(duration.toMillis()); // 1010
System.out.println("----------------------------------------------");
LocalTime lt1 = LocalTime.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LocalTime lt2 = LocalTime.now();
Duration duration2 = Duration.between(lt1, lt2);
System.out.println(duration2); // PT1.001S
System.out.println(duration2.toMillis()); // 1001
}
@Test
public void test4() {
LocalDate ld1 = LocalDate.of(2020,1,1);
LocalDate ld2 = LocalDate.now();
Period period = Period.between(ld1, ld2);
System.out.println(period); // P1Y4M3D
System.out.println(period.getYears()); // 1
System.out.println(period.getMonths()); // 4
System.out.println(period.getDays()); // 3
}
}
19. Java8新特性_新时间和日期 API-时间校正器
package day03.com.lm.java8;
import org.junit.Test;
import java.time.*;
import java.time.temporal.TemporalAdjusters;
public class TestNewDateAPI {
//TemporalAdjuster : 时间校正器
@Test
public void test5() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); // 2021-05-04T16:03:14.880
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2); // 2021-05-10T16:03:14.880
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3); // 2021-05-09T16:03:14.880
//自定义:下一个工作日
LocalDateTime nextWorkDay = ldt.with((l) -> {
LocalDateTime ldt4 = (LocalDateTime) l;
DayOfWeek dow = ldt4.getDayOfWeek();
if (dow.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
} else if (dow.equals(DayOfWeek.SATURDAY)) {
return ldt4.plusDays(2);
} else {
return ldt4.plusDays(1);
}
});
System.out.println(nextWorkDay); // 2021-05-05T16:03:14.880
}
}
20. Java8新特性_新时间和日期 API-时间格式化与时区的处理
package day03.com.lm.java8;
import org.junit.Test;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.Set;
public class TestNewDateAPI {
//ZonedDate、ZonedTime、ZonedDateTime
@Test
public void test7() {
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(str -> System.out.print(str+" "));
// Asia/Aden America/Cuiaba Etc/GMT+9 Etc/GMT+8 Africa/Nairobi America/Marigot Asia/Aqtau
// Pacific/Kwajalein America/El_Salvador Asia/Pontianak Africa/Cairo Pacific/Pago_Pago Africa/Mbabane
// Asia/Kuching Pacific/Honolulu Pacific/Rarotonga America/Guatemala Australia/Hobart Europe/London
// America/Belize America/Panama Asia/Chungking America/Managua America/Indiana/Petersburg Asia/Yerevan
// Europe/Brussels GMT Europe/Warsaw America/Chicago Asia/Kashgar Chile/Continental Pacific/Yap CET
// Etc/GMT-1 Etc/GMT-0 Europe/Jersey America/Tegucigalpa Etc/GMT-5 Europe/Istanbul America/Eirunepe
// Etc/GMT-4 America/Miquelon Etc/GMT-3 Europe/Luxembourg Etc/GMT-2 Etc/GMT-9
// America/Argentina/Catamarca Etc/GMT-8 Etc/GMT-7 Etc/GMT-6 Europe/Zaporozhye Canada/Yukon
// Canada/Atlantic Atlantic/St_Helena Australia/Tasmania Libya Europe/Guernsey America/Grand_Turk
// US/Pacific-New Asia/Samarkand America/Argentina/Cordoba Asia/Phnom_Penh Africa/Kigali Asia/Almaty
// US/Alaska Asia/Dubai Europe/Isle_of_Man America/Araguaina Cuba Asia/Novosibirsk
// America/Argentina/Salta Etc/GMT+3 Africa/Tunis Etc/GMT+2 Etc/GMT+1 Pacific/Fakaofo Africa/Tripoli
// Etc/GMT+0 Israel Africa/Banjul Etc/GMT+7 Indian/Comoro Etc/GMT+6 Etc/GMT+5 Etc/GMT+4
// Pacific/Port_Moresby US/Arizona Antarctica/Syowa Indian/Reunion Pacific/Palau Europe/Kaliningrad
// America/Montevideo Africa/Windhoek Asia/Karachi Africa/Mogadishu Australia/Perth Brazil/East
// Etc/GMT Asia/Chita Pacific/Easter Antarctica/Davis Antarctica/McMurdo Asia/Macao America/Manaus
// Africa/Freetown Europe/Bucharest Asia/Tomsk America/Argentina/Mendoza Asia/Macau Europe/Malta
// Mexico/BajaSur Pacific/Tahiti Africa/Asmera Europe/Busingen America/Argentina/Rio_Gallegos
// Africa/Malabo Europe/Skopje America/Catamarca America/Godthab Europe/Sarajevo Australia/ACT GB-Eire
// Africa/Lagos America/Cordoba Europe/Rome Asia/Dacca Indian/Mauritius Pacific/Samoa America/Regina
// America/Fort_Wayne America/Dawson_Creek Africa/Algiers Europe/Mariehamn America/St_Johns
// America/St_Thomas Europe/Zurich America/Anguilla Asia/Dili America/Denver Africa/Bamako
// Europe/Saratov GB Mexico/General Pacific/Wallis Europe/Gibraltar Africa/Conakry Africa/Lubumbashi
// Asia/Istanbul America/Havana NZ-CHAT Asia/Choibalsan America/Porto_Acre Asia/Omsk Europe/Vaduz
// US/Michigan Asia/Dhaka America/Barbados Europe/Tiraspol Atlantic/Cape_Verde Asia/Yekaterinburg
// America/Louisville Pacific/Johnston Pacific/Chatham Europe/Ljubljana America/Sao_Paulo Asia/Jayapura
// America/Curacao Asia/Dushanbe America/Guyana America/Guayaquil America/Martinique Portugal
// Europe/Berlin Europe/Moscow Europe/Chisinau America/Puerto_Rico America/Rankin_Inlet Pacific/Ponape
// Europe/Stockholm Europe/Budapest America/Argentina/Jujuy Australia/Eucla Asia/Shanghai Universal
// Europe/Zagreb America/Port_of_Spain Europe/Helsinki Asia/Beirut Asia/Tel_Aviv Pacific/Bougainville
// US/Central Africa/Sao_Tome Indian/Chagos America/Cayenne Asia/Yakutsk Pacific/Galapagos
// Australia/North Europe/Paris Africa/Ndjamena Pacific/Fiji America/Rainy_River Indian/Maldives
// Australia/Yancowinna SystemV/AST4 Asia/Oral America/Yellowknife Pacific/Enderbury America/Juneau
// Australia/Victoria America/Indiana/Vevay Asia/Tashkent Asia/Jakarta Africa/Ceuta Asia/Barnaul
// America/Recife America/Buenos_Aires America/Noronha America/Swift_Current Australia/Adelaide
// America/Metlakatla Africa/Djibouti America/Paramaribo Europe/Simferopol Europe/Sofia
// Africa/Nouakchott Europe/Prague America/Indiana/Vincennes Antarctica/Mawson America/Kralendijk
// Antarctica/Troll Europe/Samara Indian/Christmas America/Antigua Pacific/Gambier America/Indianapolis
// America/Inuvik America/Iqaluit Pacific/Funafuti UTC Antarctica/Macquarie Canada/Pacific
// America/Moncton Africa/Gaborone Pacific/Chuuk Asia/Pyongyang America/St_Vincent Asia/Gaza
// Etc/Universal PST8PDT Atlantic/Faeroe Asia/Qyzylorda Canada/Newfoundland America/Kentucky/Louisville
// America/Yakutat Asia/Ho_Chi_Minh Antarctica/Casey Europe/Copenhagen Africa/Asmara Atlantic/Azores
// Europe/Vienna ROK Pacific/Pitcairn America/Mazatlan Australia/Queensland Pacific/Nauru
// Europe/Tirane Asia/Kolkata SystemV/MST7 Australia/Canberra MET Australia/Broken_Hill Europe/Riga
// America/Dominica Africa/Abidjan America/Mendoza America/Santarem Kwajalein America/Asuncion
// Asia/Ulan_Bator NZ America/Boise Australia/Currie EST5EDT Pacific/Guam Pacific/Wake
// Atlantic/Bermuda America/Costa_Rica America/Dawson Asia/Chongqing Eire Europe/Amsterdam
// America/Indiana/Knox America/North_Dakota/Beulah Africa/Accra Atlantic/Faroe Mexico/BajaNorte
// America/Maceio Etc/UCT Pacific/Apia GMT0 America/Atka Pacific/Niue Canada/East-Saskatchewan
// Australia/Lord_Howe Europe/Dublin Pacific/Truk MST7MDT America/Monterrey America/Nassau
// America/Jamaica Asia/Bishkek America/Atikokan Atlantic/Stanley Australia/NSW US/Hawaii SystemV/CST6
// Indian/Mahe Asia/Aqtobe America/Sitka Asia/Vladivostok Africa/Libreville Africa/Maputo Zulu
// America/Kentucky/Monticello Africa/El_Aaiun Africa/Ouagadougou America/Coral_Harbour
// Pacific/Marquesas Brazil/West America/Aruba America/North_Dakota/Center America/Cayman
// Asia/Ulaanbaatar Asia/Baghdad Europe/San_Marino America/Indiana/Tell_City America/Tijuana
// Pacific/Saipan SystemV/YST9 Africa/Douala America/Chihuahua America/Ojinaga Asia/Hovd
// America/Anchorage Chile/EasterIsland America/Halifax Antarctica/Rothera America/Indiana/Indianapolis
// US/Mountain Asia/Damascus America/Argentina/San_Luis America/Santiago Asia/Baku
// America/Argentina/Ushuaia Atlantic/Reykjavik Africa/Brazzaville Africa/Porto-Novo America/La_Paz
// Antarctica/DumontDUrville Asia/Taipei Antarctica/South_Pole Asia/Manila Asia/Bangkok
// Africa/Dar_es_Salaam Poland Atlantic/Madeira Antarctica/Palmer America/Thunder_Bay
// Africa/Addis_Ababa Asia/Yangon Europe/Uzhgorod Brazil/DeNoronha Asia/Ashkhabad Etc/Zulu
// America/Indiana/Marengo America/Creston America/Punta_Arenas America/Mexico_City Antarctica/Vostok
// Asia/Jerusalem Europe/Andorra US/Samoa PRC Asia/Vientiane Pacific/Kiritimati America/Matamoros
// America/Blanc-Sablon Asia/Riyadh Iceland Pacific/Pohnpei Asia/Ujung_Pandang Atlantic/South_Georgia
// Europe/Lisbon Asia/Harbin Europe/Oslo Asia/Novokuznetsk CST6CDT Atlantic/Canary America/Knox_IN
// Asia/Kuwait SystemV/HST10 Pacific/Efate Africa/Lome America/Bogota America/Menominee America/Adak
// Pacific/Norfolk Europe/Kirov America/Resolute Pacific/Tarawa Africa/Kampala Asia/Krasnoyarsk
// Greenwich SystemV/EST5 America/Edmonton Europe/Podgorica Australia/South Canada/Central
// Africa/Bujumbura America/Santo_Domingo US/Eastern Europe/Minsk Pacific/Auckland Africa/Casablanca
// America/Glace_Bay Canada/Eastern Asia/Qatar Europe/Kiev Singapore Asia/Magadan SystemV/PST8
// America/Port-au-Prince Europe/Belfast America/St_Barthelemy Asia/Ashgabat Africa/Luanda
// America/Nipigon Atlantic/Jan_Mayen Brazil/Acre Asia/Muscat Asia/Bahrain Europe/Vilnius
// America/Fortaleza Etc/GMT0 US/East-Indiana America/Hermosillo America/Cancun Africa/Maseru
// Pacific/Kosrae Africa/Kinshasa Asia/Kathmandu Asia/Seoul Australia/Sydney America/Lima
// Australia/LHI America/St_Lucia Europe/Madrid America/Bahia_Banderas America/Montserrat Asia/Brunei
// America/Santa_Isabel Canada/Mountain America/Cambridge_Bay Asia/Colombo Australia/West
// Indian/Antananarivo Australia/Brisbane Indian/Mayotte US/Indiana-Starke Asia/Urumqi US/Aleutian
// Europe/Volgograd America/Lower_Princes America/Vancouver Africa/Blantyre America/Rio_Branco
// America/Danmarkshavn America/Detroit America/Thule Africa/Lusaka Asia/Hong_Kong Iran
// America/Argentina/La_Rioja Africa/Dakar SystemV/CST6CDT America/Tortola America/Porto_Velho
// Asia/Sakhalin Etc/GMT+10 America/Scoresbysund Asia/Kamchatka Asia/Thimbu Africa/Harare Etc/GMT+12
// Etc/GMT+11 Navajo America/Nome Europe/Tallinn Turkey Africa/Khartoum Africa/Johannesburg
// Africa/Bangui Europe/Belgrade Jamaica Africa/Bissau Asia/Tehran WET Europe/Astrakhan Africa/Juba
// America/Campo_Grande America/Belem Etc/Greenwich Asia/Saigon America/Ensenada Pacific/Midway
// America/Jujuy Africa/Timbuktu America/Bahia America/Goose_Bay America/Virgin America/Pangnirtung
// Asia/Katmandu America/Phoenix Africa/Niamey America/Whitehorse Pacific/Noumea Asia/Tbilisi
// America/Montreal Asia/Makassar America/Argentina/San_Juan Hongkong UCT Asia/Nicosia
// America/Indiana/Winamac SystemV/MST7MDT America/Argentina/ComodRivadavia America/Boa_Vista
// America/Grenada Asia/Atyrau Australia/Darwin Asia/Khandyga Asia/Kuala_Lumpur Asia/Famagusta
// Asia/Thimphu Asia/Rangoon Europe/Bratislava Asia/Calcutta America/Argentina/Tucuman Asia/Kabul
// Indian/Cocos Japan Pacific/Tongatapu America/New_York Etc/GMT-12 Etc/GMT-11 Etc/GMT-10
// SystemV/YST9YDT Europe/Ulyanovsk Etc/GMT-14 Etc/GMT-13 W-SU America/Merida EET America/Rosario
// Canada/Saskatchewan America/St_Kitts Arctic/Longyearbyen America/Fort_Nelson America/Caracas
// America/Guadeloupe Asia/Hebron Indian/Kerguelen SystemV/PST8PDT Africa/Monrovia Asia/Ust-Nera Egypt
// Asia/Srednekolymsk America/North_Dakota/New_Salem Asia/Anadyr Australia/Melbourne Asia/Irkutsk
// America/Shiprock America/Winnipeg Europe/Vatican Asia/Amman Etc/UTC SystemV/AST4ADT Asia/Tokyo
// America/Toronto Asia/Singapore Australia/Lindeman America/Los_Angeles SystemV/EST5EDT Pacific/Majuro
// America/Argentina/Buenos_Aires Europe/Nicosia Pacific/Guadalcanal Europe/Athens US/Pacific
// Europe/Monaco
}
@Test
public void test8() {
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt); // 2021-05-08T00:27:56.188
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Asia/Urumqi"));
System.out.println(ldt1); // 2021-05-07T22:27:56.189
LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Asia/Urumqi"));
ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Urumqi"));
System.out.println(zdt); // 2021-05-07T22:27:56.189+06:00[Asia/Urumqi]
}
}
21. Java8新特性_重复注解与类型注解
重复注解与类型注解
Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。
package day03.com.lm.java8;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "minge";
}
package day03.com.lm.java8;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
package day03.com.lm.java8;
import org.junit.Test;
import java.lang.reflect.Method;
/**
* 重复注解与类型注解
*/
public class TestAnnotation {
//checker framework
private /*@NonNull*/ Object obj = null;
@Test
public void test1() throws Exception {
Class<TestAnnotation> clazz = TestAnnotation.class;
Method m1 = clazz.getMethod("show");
MyAnnotation[] mas = m1.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation myAnnotation : mas) {
System.out.println(myAnnotation.value());
}
}
@MyAnnotation("Hello")
@MyAnnotation("World")
public void show(@MyAnnotation("abc") String str) {
}
}