1. Java 8
1.1 生态
- Lambda 表达式
- 函数式接口
- 方法引用 / 构造器引用
- Stream API
- 接口中的默认方法 / 静态方法
- 新时间日期 API
- 其他新特性
1.2 新特性
-
速度更快
-
代码更少
-
强大的 Stream API
-
便于并行
-
最大化减少空指针异常 Optional (Kotlin ?)
注:其中最为核心的为 Lambda 表达式与 Stream API
1.3 温故而知新
- Hashmap 底层结构/原理 老话题不再阐述 …
- 并发hashmap …
- Java虚拟机 …
- Java内存模型 …
2. Lambda
2.1 匿名函数
Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样传递);可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升。
2.2 匿名内部类
@Test
public void test01(){
//匿名内部类
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
@Override
public boolean equals(Object obj) {
return false;
}
};
//调用
TreeSet<Integer> set = new TreeSet<>(comparator);
}
2.3 Lambda
@Test
public void test02(){
// Lambda 表达式
Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
TreeSet<Integer> set = new TreeSet<>(comparator);
}
演变过程:
- 垃圾代码 --> 策略模式 --> 匿名内部类 --> Lambda表达式
import org.junit.Test;
import java.util.*;
/**
* Lambda 表达式
*/
public class TestLambda {
// 原来的匿名内部类
@Test
public void test1() {
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> integers = new TreeSet<>(comparator);
}
// Lambda 表达式
public void test2() {
Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> integers = new TreeSet<>(comparator);
}
// ---------------案例1 start-------------------
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",28,5555.99),
new Employee("王五",38,7777.99),
new Employee("赵六",50,3333.99),
new Employee("田七",8,1111.99)
);
// 需求:获取当前公司中员工年龄大于 35 的员工信息
// 以前做法
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;
}
@Test
public void test3() {
List<Employee> emp = filterEmployees(this.employees);
System.out.println("过滤后得到的员工:" + emp);
}
// 需求:获取当前公司中员工工资大于 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;
}
// 优化方式一: 使用设计模式
// 策略设计模式
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 test4() {
List<Employee> emp1 = filterEmployee(this.employees, new FilterEmployeeByAge());
System.out.println(emp1.toString());
List<Employee> emp2 = filterEmployee(this.employees, new FilterEmployeeBySalary());
System.out.println(emp2.toString());
}
// 优化方式二:匿名内部类
@Test
public void test5() {
List<Employee> list = filterEmployee(this.employees, new MyPredicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary() >= 5000;
}
});
System.out.println(list.toString());
}
// 优化方式三: 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)
.forEach(System.out::println);
System.out.println("--------打印名字--------");
employees.stream().map(Employee::getName).forEach(System.out::println);
}
// ---------------案例1 end-------------------
}
基础语法:
- 操作符:->
- 左侧:参数列表
- 右侧:执行代码块 / Lambda 体
口诀:
- 写死小括号,拷贝右箭头,落地大括号
- 左右遇一括号省
- 左侧推断类型省
语法格式:
- 无参数,无返回值:() -> sout
例如 Runnable接口:
public class Test02 {
int num = 10; //jdk 1.7以前 必须final修饰
@Test
public void test01(){
//匿名内部类
new Runnable() {
@Override
public void run() {
//在局部类中引用同级局部变量
//只读
System.out.println("Hello World" + num);
}
};
}
@Test
public void test02(){
//语法糖
Runnable runnable = () -> {
System.out.println("Hello Lambda");
};
}
}
- 有一个参数,无返回值
@Test
public void test03(){
Consumer<String> consumer = (a) -> System.out.println(a);
consumer.accept("我觉得还行!");
}
- 有一个参数,无返回值 (小括号可以省略不写)
@Test
public void test03(){
Consumer<String> consumer = a -> System.out.println(a);
consumer.accept("我觉得还行!");
}
- 有两个及以上的参数,有返回值,并且 Lambda 体中有多条语句
@Test
public void test04(){
Comparator<Integer> comparator = (a, b) -> {
System.out.println("比较接口");
return Integer.compare(a, b);
};
}
- 有两个及以上的参数,有返回值,并且 Lambda 体中只有1条语句 (大括号 与 return 都可以省略不写)
@Test
public void test04(){
Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
}
- Lambda 表达式 参数的数据类型可以省略不写 Jvm可以自动进行 “类型推断”
函数式接口:
- 接口中只有一个抽象方法的接口 @FunctionalIterface
测试:
- 定义一个函数式接口:
@FunctionalInterface
public interface MyFun {
Integer count(Integer a, Integer b);
}
- 用一下:
@Test
public void test05(){
MyFun myFun1 = (a, b) -> a + b;
MyFun myFun2 = (a, b) -> a - b;
MyFun myFun3 = (a, b) -> a * b;
MyFun myFun4 = (a, b) -> a / b;
}
- 再用一下:
public Integer operation(Integer a, Integer b, MyFun myFun){
return myFun.count(a, b);
}
@Test
public void test06(){
Integer result = operation(1, 2, (x, y) -> x + y);
System.out.println(result);
}
测试
import org.junit.jupiter.api.Test;
import java.util.Comparator;
import java.util.function.Consumer;
/**
* 一、Lambda 表达式的基础语法: Java8中引入了一个新的操作符 "->",该操作符称为箭头操作符或者 Lambda 操作符
* 箭头操作符将 Lambda 表达式拆分成两部分:
* 左侧: Lambda 表达式的参数列表
* 右侧: Lambda 表达式中所需执行的功能,即 Lambda 体
*
* 语法格式一: 无参数,无返回值
* 例: () -> System.out.println("hello");
* 语法格式二: 有一个参数,并且无返回值
* 例: (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 = (x,y) -> Integer.compare(x,y);
*
* 总结:
* 左右遇一括号省
* 左侧推断类型省
* 能省则省
*
*
* 二、Lambda 表达式需要 "函数式接口" 的支持
* 函数式接口: 接口中只有一个抽象方法的接口,称为函数式接口
* 可以使用注解 @FunctionalInterface 修饰,可以检查是否是函数式接口
*
*/
public class TestLambda2 {
@Test
public void test1() {
int num = 0; // 在内部类中使用局部变量,jdk 1.7以前,必须是final修饰,1.8之后可以省略
// 内部类形式
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!" + num);
}
};
r.run();
// Lambda 形式
Runnable r1 = () -> System.out.println("Hello World!" + num);
r1.run();
}
@Test
public void test2() {
Consumer<String> con = (x) -> System.out.println(x);
Consumer<String> con2 = x -> System.out.println(x); // 一个参数,小括号可以省略不写
con.accept("hello world!");
}
@Test
public void test3() {
Comparator<Integer> com = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
}
@Test
public void test4() {
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
}
@Test
public void test5() {
Comparator<Integer> com = (Integer x,Integer y) -> Integer.compare(x,y);
}
// 需求:对一个数进行运算
@Test
public void test6() {
Integer num = operation(10, (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);
}
}
函数式接口 @FunctionalInterface
@FunctionalInterface
public interface MyFun<T> {
public Integer getValue(Integer num);
}
2.4 案例
**案例一:**调用 Collections.sort() 方法,通过定制排序 比较两个 Employee (先按照年龄比,年龄相同按照姓名比),使用 Lambda 表达式作为参数传递
- 定义实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String name;
private Integer age;
private Double salary;
}
- 定义 List 传入数据
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
);
- @Test
@Test
public void test01(){
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);
}
}
**案例二:**声明函数式接口,接口中声明抽象方法,String getValue(String str); 声明类 TestLambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值;再将一个字符串的第二个和第四个索引位置进行截取字串
**案例三:**声明一个带两个泛型的函数式接口,泛型类型为<T, R> T 为参数,R 为返回值;接口中声明对应的抽象方法;在 TestLambda 类中声明方法,使用接口作为参数,计算两个 Long 类型参数的和;在计算两个 Long 类型参数的乘积
import com.lambda.Employee;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 案例
*/
public class TestLambdaExer {
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",28,5555.99),
new Employee("王五",38,7777.99),
new Employee("赵六",50,3333.99),
new Employee("田七",8,1111.99)
);
/**
* 调用 Collections.sort() 方法,通过定制排序 比较两个 Employee (先按照年龄比,年龄相同按照姓名比),使用 Lambda 表达式作为参数传递
*/
@Test
public void test1() {
Collections.sort(employees, (e1,e2) -> {
int n1 = e1.getAge() - e2.getAge();
int n2 = e1.getName().compareTo(e2.getName());
return n1 == 0 ? n2 : n1;
// if (e1.getAge() == e2.getAge()) {
// return e1.getName().compareTo(e2.getName());
// } else {
// return Integer.compare(e1.getAge(),e2.getAge());
// }
});
System.out.println(employees.toString());
}
/**
* 声明函数式接口,接口中声明抽象方法,String getValue(String str); 声明类 TestLambda,类中编写方法使用接口作为参数,
* 将一个字符串转换成大写,并作为方法的返回值;再将一个字符串的第二个和第四个索引位置进行截取字串
*/
@Test
public void test2() {
String s = toUpper("hello world!", str -> str.toUpperCase());
System.out.println(s);
System.out.println(s.substring(1,5));
String s1 = toUpper("hello world!", str -> str.substring(1, 5));
System.out.println(s1);
}
private String toUpper(String str, MyFunction myFunction) {
return myFunction.getValue(str);
}
/**
* 声明一个带两个泛型的函数式接口,泛型类型为<T, R> T 为参数,R 为返回值;接口中声明对应的抽象方法;
* 在 TestLambda 类中声明方法,使用接口作为参数,计算两个 Long 类型参数的和;在计算两个 Long 类型参数的乘积
*/
@Test
public void test3() {
op(100L,200L,(l1,l2) -> l1 + l2);
op(4L,5L,(l1,l2) -> l1 * l2);
}
private void op(Long l1,Long l2,MyFunction2<Long,Long> mf) {
System.out.println(mf.getValue(l1,l2));
}
}
@FunctionalInterface
public interface MyFunction {
public String getValue(String str);
}
@FunctionalInterface
public interface MyFunction2<T,R> {
public R getValue(T t1,T t2);
}
3. 函数式接口
Java内置四大核心函数式接口:
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer 消费型接口 | T | void | 对类型为T的对象应用操作:void accept(T t) |
Supplier 提供型接口 | 无 | T | 返回类型为T的对象:T get() |
Function<T, R> 函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t) |
Predicate 断言型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t) |
3.1 消费型接口
@Test
public void test01(){
//Consumer
Consumer<Integer> consumer = (x) -> System.out.println("消费型接口" + x);
//test
consumer.accept(100);
}
3.2 提供型接口
@Test
public void test02(){
List<Integer> list = new ArrayList<>();
List<Integer> integers = Arrays.asList(1,2,3);
list.addAll(integers);
//Supplier<T>
Supplier<Integer> supplier = () -> (int)(Math.random() * 10);
list.add(supplier.get());
System.out.println(supplier);
for (Integer integer : list) {
System.out.println(integer);
}
}
3.3 函数型接口
@Test
public void test03(){
//Function<T, R>
String oldStr = "abc123456xyz";
Function<String, String> function = (s) -> s.substring(1, s.length()-1);
//test
System.out.println(function.apply(oldStr));
}
3.4 断言型接口
@Test
public void test04(){
//Predicate<T>
Integer age = 35;
Predicate<Integer> predicate = (i) -> i >= 35;
if (predicate.test(age)){
System.out.println("你该退休了");
} else {
System.out.println("我觉得还OK啦");
}
}
3.5 其他接口
3.6测试
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* java8 内置的四大核心函数式接口
*
* 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 TestFunctionalInterfaces {
/**
* Consumer<T> : 消费型接口
*/
@Test
public void test1() {
happy(100, (x) -> System.out.println("消费:" + x*10));
}
public void happy(double money, Consumer<Double> consumer) {
consumer.accept(money);
}
/**
* Supplier<T> : 供给型接口
*/
@Test
public void test2() {
List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
System.out.println(numList.toString());
}
// 需求:产生指定个数的整数,并放入集合中
public List<Integer> getNumList(int num, Supplier<Integer> supplier) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
Integer n = supplier.get();
list.add(n);
}
return list;
}
/**
* Function<T, R> : 函数型接口
*/
@Test
public void test3() {
// 转成大写
String s = strHandler("hello world!", (x) -> x.toUpperCase());
System.out.println(s);
// 去除首尾空格
String s1 = strHandler("\t\t\t 尚硅谷", (str) -> str.trim());
System.out.println(s1);
}
// 需求: 用于处理字符串
public String strHandler(String str, Function<String,String> function) {
return function.apply(str);
}
/**
* Predicate<T> : 断言型接口
*/
@Test
public void test4() {
List<String> list = filterStr(Arrays.asList("Hello", "atguigu", "Lambda","www","ok"), (str) -> str.length() > 5);
System.out.println(list.toString());
}
// 需求:将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> list, Predicate<String> pre) {
List<String> list1 = new ArrayList<>();
for (String s : list) {
if (pre.test(s)) {
list1.add(s);
}
}
return list1;
}
}
4. 引用
4.1 方法引用
**定义:**若 Lambda 表达式体中的内容已有方法实现,则我们可以使用“方法引用”
语法格式:
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
对象::实例方法
@Test
public void test01(){
PrintStream ps = System.out;
Consumer<String> con1 = (s) -> ps.println(s);
con1.accept("aaa");
Consumer<String> con2 = ps::println;
con2.accept("bbb");
}
**注意:**Lambda 表达实体中调用方法的参数列表、返回类型必须和函数式接口中抽象方法保持一致
类::静态方法
@Test
public void test02(){
Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
System.out.println(com1.compare(1, 2));
Comparator<Integer> com2 = Integer::compare;
System.out.println(com2.compare(2, 1));
}
类::实例方法
@Test
public void test03(){
BiPredicate<String, String> bp1 = (x, y) -> x.equals(y);
System.out.println(bp1.test("a","b"));
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("c","c"));
}
**条件:**Lambda 参数列表中的第一个参数是方法的调用者,第二个参数是方法的参数时,才能使用 ClassName :: Method
4.2 构造器引用
格式:
- ClassName :: new
@Test
public void test04(){
Supplier<List> sup1 = () -> new ArrayList();
Supplier<List> sup2 = ArrayList::new;
}
**注意:**需要调用的构造器的参数列表要与函数时接口中抽象方法的参数列表保持一致
4.3 数组引用
语法:
- Type :: new;
4.4测试
import com.lambda.Employee;
import org.junit.jupiter.api.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* 一、方法引用: 若 Lambda 体中的内容有方法已经实现了,我们可以使用"方法引用"
* (可以理解为方法引用是 Lambda 表达式的另外一种表现形式)
*
* 主要有三种语法格式:
* 对象::实例方法名
* 类::静态方法名
* 类::实例方法名
*
* 注意
* ①: Lambda 体种调用方法的参数列表与返回值类型,要与函数式接口抽象方法的函数列表和返回值类型保持一致
* ②: 若 Lambda 参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName::method (即 类::实例方法名)
*
*
*
* 二、构造器引用
* 格式: ClassName::new (类名::new)
* 注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致
*
* 三、数组引用
* Type[]::new (数组类型::new)
*/
public class TestMethodRef {
@Test
public void test1() {
Consumer<String> con = (x) -> System.out.println(x);
/**
* 对象::实例方法名
* Lambda 表达实体中调用方法的参数列表、返回类型必须和函数式接口中抽象方法保持一致
* 此处 Consumer 的 void accept(T t) 方法参数是一个泛型,返回值为void
* public void println(String x) 方法参数也只有一个,无返回值
*/
PrintStream ps = System.out;
Consumer<String> con1 = ps::println;
con1.accept("abcdefg");
// Consumer<String> con2 = System.out::println;
}
@Test
public void test2() {
Employee employee = new Employee();
Supplier<String> sup = () -> employee.getName();
String str = sup.get();
System.out.println(str);
Supplier<Integer> sup2 = employee::getAge;
Integer num = sup2.get();
System.out.println(num);
}
/**
* 类::静态方法名
*/
@Test
public void test3() {
// Lambda 形式
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
// 类::静态方法名 形式
Comparator<Integer> com1 = Integer::compare;
}
/**
* 类::实例方法名
* 规则:第一个参数是实例方法的调用者,第二个参数是这个实例方法的参数值,这种情况下就可以使用 类::实例方法名
*
* 此例中 x是实例equals方法的调用者,y是实例方法的参数
*/
@Test
public void test4() {
// Lambda 形式
BiPredicate<String,String> bp = (x,y) -> x.equals(y);
// 类::实例方法名 形式
BiPredicate<String,String> bp2 = String::equals;
}
// -----------------------------------------------------------------
/**
* 构造器引用
*/
@Test
public void test5() {
// Lambda 形式
Supplier<Employee> sup = () -> new Employee();
// 构造器引用
// 调用哪个构造器取决于函数式接口方法的参数列表
Supplier<Employee> sup2 = Employee::new;
Employee employee = sup2.get();
System.out.println(employee.toString());
}
// -----------------------------------------------------------
/**
* 数组引用
*/
@Test
public void test6() {
// Lambda 形式
Function<Integer,String[]> fun = (x) -> new String[x];
String[] apply = fun.apply(10);
System.out.println(apply.length);
// 数组引用
Function<Integer,String[]> fun2 = String[]::new;
String[] apply1 = fun2.apply(20);
System.out.println(apply1);
}
}
5. Stream API
5.1 创建
什么是 Stream?m
Stream的操作步骤:
创建流:(的几种方法如下)
/**
* 创建流
*/
@Test
public void test01(){
/**
* 集合流
* - Collection.stream() 串行流
* - Collection.parallelStream() 并行流
*/
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//数组流
//Arrays.stream(array)
String[] strings = new String[10];
Stream<String> stream2 = Arrays.stream(strings);
//Stream 静态方法
//Stream.of(...)
Stream<Integer> stream3 = Stream.of(1, 2, 3);
//无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (i) -> ++i+i++);
stream4.forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
}
/**
* 创建 Stream
* 四种方法:
*/
@Test
public void test1() {
// 1.可以通过 Collection 系列集合提供的 stream()【串行流】 或 parallelStream() 【并行流】
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
// 2.通过 Arrays 中的静态方法 stream() 获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream1 = Arrays.stream(emps);
// 3.通过 Stream 类中的静态方法 of()
Stream<String> stream2 = Stream.of("aa", "bb", "cc");
Stream<Employee> stream3 = Stream.of(emps);
// 4.创建无限流
// 4.1迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
// stream4.forEach(System.out::println); // 无限输出
// stream4.limit(10).forEach(System.out::println); // 产生10个
// 4.2生成
Stream<Double> stream5 = Stream.generate(() -> Math.random());
// stream5.forEach(System.out::println); // 无限产生随机数
stream5.limit(10).forEach(System.out::println); // 产生10个随机数
}
5.2 筛选 / 切片 —中间操作
中间操作:
- filter:接收 Lambda ,从流中排除某些元素
- limit:截断流,使其元素不超过给定数量
- skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
- distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
);
@Test
public void test01(){
emps.stream()
.filter((x) -> x.getAge() > 35)
.limit(3) //短路?达到满足不再内部迭代
.distinct()
.skip(1)
.forEach(System.out::println);
}
Stream的中间操作:
- 内部迭代:迭代操作由 Stream API 完成
- 外部迭代:我们通过迭代器完成
5.3 映射 — 中间操作
- map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
- flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流
map:
@Test
public void test02(){
List<String> list = Arrays.asList("a", "b", "c");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
}
flatMap:
public Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (char c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
@Test
public void test03(){
List<String> list = Arrays.asList("a", "b", "c");
Test02 test02 = new Test02();
list.stream()
.flatMap(test02::filterCharacter)
.forEach(System.out::println);
}
5.4 排序 — 中间操作
- sorted():自然排序
- sorted(Comparator c):定制排序
Comparable:自然排序
@Test
public void test04(){
List<Integer> list = Arrays.asList(1,2,3,4,5);
list.stream()
.sorted() //comparaTo()
.forEach(System.out::println);
}
Comparator:定制排序
@Test
public void test05(){
emps.stream()
.sorted((e1, e2) -> { //compara()
if (e1.getAge().equals(e2.getAge())){
return e1.getName().compareTo(e2.getName());
} else {
return e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
}
5.5 查找 / 匹配 —终止操作
终止操作:
- allMatch:检查是否匹配所有元素
- anyMatch:检查是否至少匹配一个元素
- noneMatch:检查是否没有匹配所有元素
- findFirst:返回第一个元素
- findAny:返回当前流中的任意元素
- count:返回流中元素的总个数
- max:返回流中最大值
- min:返回流中最小值
public enum Status {
FREE, BUSY, VOCATION;
}
@Test
public void test01(){
List<Status> list = Arrays.asList(Status.FREE, Status.BUSY, Status.VOCATION);
boolean flag1 = list.stream()
.allMatch((s) -> s.equals(Status.BUSY));
System.out.println(flag1);
boolean flag2 = list.stream()
.anyMatch((s) -> s.equals(Status.BUSY));
System.out.println(flag2);
boolean flag3 = list.stream()
.noneMatch((s) -> s.equals(Status.BUSY));
System.out.println(flag3);
// 避免空指针异常
Optional<Status> op1 = list.stream()
.findFirst();
// 如果Optional为空 找一个替代的对象
Status s1 = op1.orElse(Status.BUSY);
System.out.println(s1);
Optional<Status> op2 = list.stream()
.findAny();
System.out.println(op2);
long count = list.stream()
.count();
System.out.println(count);
}
5.6 归约 / 收集—终止操作
- 归约:reduce(T identity, BinaryOperator) / reduce(BinaryOperator) 可以将流中的数据反复结合起来,得到一个值
- 收集:collect 将流转换成其他形式;接收一个 Collector 接口的实现,用于给流中元素做汇总的方法
5.6.1 reduce 规约:
/**
* Java:
* - reduce:需提供默认值(初始值)
* Kotlin:
* - fold:不需要默认值(初始值)
* - reduce:需提供默认值(初始值)
*/
@Test
public void test01(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
Integer integer = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(integer);
}
/**
* 规约
* reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ———— 可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test10() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
/**
* T reduce(T identity, BinaryOperator<T> accumulator) 使用提供的身份值和 associative累积功能对此流的元素执行 reduction ,并返回减小的值
* 此处先将 0 赋值给x,y从集合中取出第一个数作为自己的值,即1,0+1=1;计算完后x的值为计算结果1,y继续从集合中取出第二个元素作为自己的值,即2,1+2=3;
* x的值为3,y为4,3+4=7;x为7,y为5,7+5=12,x为12.....,依此计算下去即可得到结果 55
*/
Integer sum = list.stream().reduce(0, (x, y) -> x + y); // 计算和
System.out.println(sum);
System.out.println("-------------------------------");
/**
* Optional<T> reduce(BinaryOperator<T> accumulator) 使用 associative累积函数对此流的元素执行 reduction ,并返回描述减小值的 Optional (如果有)。
* 注:结果有可能为空的都被封装成 Optional 对象
*/
Optional<Double> reduce = emps.stream().map(Employee::getSalary).reduce(Double::sum); // 计算工资总和
System.out.println(reduce.get());
}
5.6.2 collect 收集:
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
);
@Test
public void test02(){
//放入List
List<String> list = emps.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list.forEach(System.out::println);
//放入Set
Set<String> set = emps.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
//放入LinkedHashSet
LinkedHashSet<String> linkedHashSet = emps.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(LinkedHashSet::new));
linkedHashSet.forEach(System.out::println);
}
@Test
public void test03(){
//总数
Long count = emps.stream()
.collect(Collectors.counting());
System.out.println(count);
//平均值
Double avg = emps.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
//总和
Double sum = emps.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
//最大值
Optional<Employee> max = emps.stream()
.collect(Collectors.maxBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
System.out.println(max.get());
//最小值
Optional<Double> min = emps.stream()
.map(Employee::getSalary)
.collect(Collectors.minBy(Double::compare));
System.out.println(min.get());
}
@Test
public void test04(){
//分组
Map<Integer, List<Employee>> map = emps.stream()
.collect(Collectors.groupingBy(Employee::getId));
System.out.println(map);
//多级分组
Map<Integer, Map<String, List<Employee>>> mapMap = emps.stream()
.collect(Collectors.groupingBy(Employee::getId, Collectors.groupingBy((e) -> {
if (e.getAge() > 35) {
return "开除";
} else {
return "继续加班";
}
})));
System.out.println(mapMap);
//分区
Map<Boolean, List<Employee>> listMap = emps.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 4321));
System.out.println(listMap);
}
@Test
public void test05(){
//总结
DoubleSummaryStatistics dss = emps.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getMax());
System.out.println(dss.getMin());
System.out.println(dss.getSum());
System.out.println(dss.getCount());
System.out.println(dss.getAverage());
//连接
String str = emps.stream()
.map(Employee::getName)
.collect(Collectors.joining("-")); //可传入分隔符
System.out.println(str);
}
收集成集合
/**
* 收集
* collect ———— 将流转换成为其他形式。接收一个Collector接口的实现,用于给Stream中元素左汇总的方法
*/
@Test
public void test11() {
// 收集成 List
List<String> nameList = emps.stream()
.map(Employee::getName)
.collect(Collectors.toList());
System.out.println(nameList.toString());
// 收集成 Set
System.out.println("----------------");
Set<String> nameSet = emps.stream().map(Employee::getName).collect(Collectors.toSet());
System.out.println(nameSet.toString());
// 收集成其他集合
System.out.println("----------------");
HashSet<String> nameHashSet = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
System.out.println(nameHashSet);
}
汇总
@Test
public void test12() {
// 总数
Long count = emps.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("---------------------------");
// 平均值
Double salaryAvg = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println("salaryAvg = " + salaryAvg);
System.out.println("---------------------------");
// 总和
DoubleSummaryStatistics salarySum = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println("salarySum = " + salarySum);
System.out.println("---------------------");
// 最大值
Optional<Employee> max = emps.stream().collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
System.out.println("max[Employee] = " + max.get());
// 最小值
Optional<Double> min = emps.stream().map(Employee::getSalary).collect(Collectors.minBy((e1, e2) -> Double.compare(e1, e2)));
System.out.println("min = " + min.get());
}
分组
// 分组
@Test
public void test13() {
// 分组
Map<Employee.Status, List<Employee>> groupStatus = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
for (Map.Entry<Employee.Status, List<Employee>> entry : groupStatus.entrySet()) {
System.out.println("entry = " + entry);
}
}
多级分组(多列分组)
// 多级分组(多列分组)
@Test
public void test14() {
// 多级分组
Map<Employee.Status, Map<String, List<Employee>>> collect = emps.stream().collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() <= 35) {
return "青年";
} else if (e.getAge() <= 50) {
return "中年";
} else {
return "老年";
}
}))); // 先按状态再按年龄分,可以继续嵌套分下去
for (Map.Entry<Employee.Status, Map<String, List<Employee>>> entry : collect.entrySet()) {
System.out.println(entry);
}
}
分片(分区),也可以多级
@Test
public void test15() {
Map<Boolean, List<Employee>> collect = emps.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
for (Map.Entry<Boolean, List<Employee>> entry : collect.entrySet()) {
System.out.println(entry);
}
}
汇总函数
// 汇总函数
@Test
public void test16() {
// 汇总函数
DoubleSummaryStatistics dss = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getCount()); // 总数
System.out.println(dss.getAverage()); // 平均值
System.out.println(dss.getMax()); // 最大值
System.out.println(dss.getMin()); // 最小值
System.out.println(dss.getSum()); // 总和
}
连接
// 连接
@Test
public void test17() {
String collect1 = emps.stream().map(Employee::getName).collect(Collectors.joining());
String collect2 = emps.stream().map(Employee::getName).collect(Collectors.joining(","));
String collect3 = emps.stream().map(Employee::getName).collect(Collectors.joining(",","-----","========="));
System.out.println(collect1);
System.out.println(collect2);
System.out.println(collect3);
}
结果:
张三李四王五赵六田七田七
张三,李四,王五,赵六,田七,田七
-----张三,李四,王五,赵六,田七,田七=========
5.7 案例
**案例一:**给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?(如:给定【1,2,3,4,5】,返回【1,4,9,16,25】)
@Test
public void test01(){
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream()
.map((x) -> x * x)
.forEach(System.out::println);
}
**案例二:**怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢?
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
);
@Test
public void test02(){
Optional<Integer> result = emps.stream()
.map((e) -> 1)
.reduce(Integer::sum);
System.out.println(result.get());
}
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* 案例
*/
public class TestExample {
/**
* 给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?(如:给定【1,2,3,4,5】,返回【1,4,9,16,25】)
*/
@Test
public void test1() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> collect = list.stream().map(item -> item * item).collect(Collectors.toList());
System.out.println(collect.toString());
// Integer[] integers = new Integer[]{1, 2, 3, 4, 5};
// List<Integer> collect1 = Arrays.stream(integers).map(item -> item * item).collect(Collectors.toList());
// System.out.println(collect1);
}
/**
* 怎样使用 map 和 reduce 数一数流中有多少个 Employee 呢?
*/
List<Employee> emps = Arrays.asList(
new Employee("张三",18,9999.99, Employee.Status.FREE),
new Employee("李四",28,5555.99, Employee.Status.BUSY),
new Employee("王五",38,7777.99, Employee.Status.VOCATION),
new Employee("赵六",50,3333.99, Employee.Status.FREE),
new Employee("田七",8,1111.99, Employee.Status.BUSY),
new Employee("田七",8,1111.99, Employee.Status.BUSY)
);
@Test
public void test2() {
Optional<Integer> count = emps.stream().map((e) -> 1).reduce(Integer::sum);
System.out.println(count.get());
}
}
5.8 并行流
- 并行流:就是把一个内容分成几个数据块,并用不同的线程分别处理每个数据块的流
- Java 8 中将并行进行了优化,我们可以很容易的对数据进行操作;Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与串行流之间切换
Fork / Join 框架:
Fork / Join 框架与传统线程池的区别:
Fork / Join 实现:
import java.util.concurrent.RecursiveTask;
/**
* 并行流
* RecursiveTask 有返回值
* RecursiveAction 无返回值
*/
public class ForkJoinCalculate extends RecursiveTask<Long> {
private static final long serialVersionUID = 1234567890L;
private long start;
private long end;
private static final long THRESHPLD = 10000;
public ForkJoinCalculate(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start;
if (length <= THRESHPLD) {
long sum = 0;
for (long i = start; i <= end; i++) {
sum += i;
}
} else {
long middle = (start + end) / 2;
ForkJoinCalculate left = new ForkJoinCalculate(start, end);
left.fork(); //拆分子任务 压入线程队列
ForkJoinCalculate right = new ForkJoinCalculate(middle + 1, end);
right.fork();
return left.join() + right.join();
}
return null;
}
}
public class TestForkJoin {
/**
* ForkJoin 框架
*/
@Test
public void test01(){
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinCalculate task = new ForkJoinCalculate(0, 100000000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start, end).getNano());
}
/**
* 普通 for循环
*/
@Test
public void test02(){
Instant start = Instant.now();
Long sum = 0L;
for (long i = 0; i < 100000000L; i++) {
sum += i;
}
Instant end = Instant.now();
System.out.println(Duration.between(start, end).getNano());
}
/**
* java8 并行流
*/
@Test
public void test3() {
Instant start = Instant.now();
long sum = LongStream.rangeClosed(0, 100000000L)
.parallel() // 并行流
.reduce(0, Long::sum);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗费时间:" + Duration.between(start,end).toMillis());
}
}
Java 8 并行流 / 串行流:
@Test
public void test03(){
//串行流(单线程):切换为并行流 parallel()
//并行流:切换为串行流 sequential()
LongStream.rangeClosed(0, 100000000L)
.parallel() //底层:ForkJoin
.reduce(0, Long::sum);
}
5.9测试
import org.junit.jupiter.api.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 一、Stream 的三个操作步骤:
* 1.创建 Stream
* 2.中间操作
* 3.终止操作(终端操作)
*/
public class TestStreamApi {
/**
* 创建 Stream
*/
@Test
public void test1() {
// 1.可以通过 Collection 系列集合提供的 stream()【串行流】 或 parallelStream() 【并行流】
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
// 2.通过 Arrays 中的静态方法 stream() 获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream1 = Arrays.stream(emps);
// 3.通过 Stream 类中的静态方法 of()
Stream<String> stream2 = Stream.of("aa", "bb", "cc");
Stream<Employee> stream3 = Stream.of(emps);
// 4.创建无限流
// 4.1迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
// stream4.forEach(System.out::println); // 无限输出
// stream4.limit(10).forEach(System.out::println); // 产生10个
// 4.2生成
Stream<Double> stream5 = Stream.generate(() -> Math.random());
// stream5.forEach(System.out::println); // 无限产生随机数
stream5.limit(10).forEach(System.out::println); // 产生10个随机数
}
// ---------------------------------中间操作 筛选与切片---------------------------------
List<Employee> employees = Arrays.asList(
new Employee("张三",18,9999.99),
new Employee("李四",28,5555.99),
new Employee("王五",38,7777.99),
new Employee("赵六",50,3333.99),
new Employee("田七",8,1111.99),
new Employee("田七",8,1111.99),
new Employee("田七",8,1111.99)
);
/**
* 中间操作
* 筛选与切片
* 1.filter ———— 接收 Lambda ,从流中排除某些元素
* 2.limit ———— 截断流,使其元素不超过给定数量
* 3.skip(n) ———— 跳过元素,返回一个扔掉前 n 个元素的流。若流中元素不足 n 个,则返回空流。与 limit(n) 互补
* 4.distinct ———— 筛选,通过流所生成的元素的 hashCode() 和 equals() 去除重复元素
*/
// 1.filter ———— 接收 Lambda ,从流中排除某些元素
@Test
public void test2() {
// 中间操作:不会执行任何操作
// 内部迭代:迭代操作由 Stream API 完成
Stream<Employee> stream1 = employees.stream().filter((e) -> {
System.out.println("Stream API 的中间操作");
return e.getAge() > 35;
}); // 中间操作不会有结果,只有遇到终止操作才会有结果
// 终止操作:一次性执行全部内容,即"惰性求值"
stream1.forEach(System.out::println); // 如果将此终止操作注释掉, System.out.println("Stream API 的中间操作");不会执行
}
// 外部迭代: 由迭代器来完成
@Test
public void test22() {
Iterator<Employee> iterator = employees.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
// 2.limit ———— 截断流,使其元素不超过给定数量
@Test
public void test3() {
employees.stream()
.filter((e) -> {
System.out.println("短路!");
return e.getSalary() > 3000;
})
.limit(2)
.forEach(System.out::println);
}
// 3.skip(n) ———— 跳过元素,返回一个扔掉前 n 个元素的流。若流中元素不足 n 个,则返回空流。与 limit(n) 互补
@Test
public void test4() {
employees.stream().filter((e) -> e.getSalary() > 3000)
.skip(2)
.forEach(System.out::println);
}
// 4.distinct ———— 筛选,通过流所生成的元素的 hashCode() 和 equals() 去除重复元素
@Test
public void test5() {
Arrays.asList(2,22,5,3,2,66,32,2,122).stream()
.distinct()
.forEach(System.out::println);
System.out.println("------对象类型--------");
// 对象类型需要重写 hashCode 和 equals 方法
// employees.stream()
// .filter(e -> e.getSalary() < 2000)
// .distinct()
// .forEach(System.out::println);
}
// ---------------------------------中间操作 映射---------------------------------
/**
* 中间操作
* 映射
* 1.map ———— 接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每一个元素上,并将其映射成一个新的元素
* 2.flatMap ———— 接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连城一个流
*/
// 1.map
@Test
public void test6() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "eee");
list.stream().map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("------------------------------");
List<String> nameList = employees.stream().map(Employee::getName).collect(Collectors.toList());
System.out.println(nameList.toString());
}
// 2.flatMap
@Test
public void test7() {
// map 将每一个字符提取出来
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "eee");
Stream<Stream<Character>> streamStream = list.stream().map(TestStreamApi::filterCharacter); // {{a,a,a},{b,b,b},...}
streamStream.forEach((sm) -> {
sm.forEach(System.out::println);
});
System.out.println("--------flatMap----------");
Stream<Character> characterStream = list.stream().flatMap(TestStreamApi::filterCharacter); // {a,a,a,b,b,b,...}
characterStream.forEach(System.out::println);
}
// 将每一个字符提取出来的方法
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (char ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
// ---------------------------------中间操作 排序---------------------------------
/**
* 中间操作
* 排序
* sorted() ———— 自然排序 (Comparable)
* sorted(Comparator com) ———— 定制排序 (Comparator)
*/
@Test
public void test8() {
List<String> list = Arrays.asList("ccc", "fff", "aaa", "ddd", "bbb");
list.stream().sorted().forEach(System.out::println);
System.out.println("-------定制排序---------");
employees.stream().sorted((e1,e2) -> {
if (e1.getAge() - e2.getAge() == 0) {
return e1.getName().compareTo(e2.getName());
} else {
return e1.getAge() - e2.getAge();
}
}).forEach(System.out::println);
}
// ---------------------------------终止操作 查找与匹配---------------------------------
List<Employee> emps = Arrays.asList(
new Employee("张三",18,9999.99, Employee.Status.FREE),
new Employee("李四",28,5555.99, Employee.Status.BUSY),
new Employee("王五",38,7777.99, Employee.Status.VOCATION),
new Employee("赵六",50,3333.99, Employee.Status.FREE),
new Employee("田七",8,1111.99, Employee.Status.BUSY),
new Employee("田七",8,1111.99, Employee.Status.BUSY)
);
/**
* 查找与匹配
* 1.allMatch ———— 检查是否匹配所有元素 (匹配所有返回true,否则false)
* 2.andMatch ———— 检查是否至少匹配一个元素
* 3.noneMath ———— 检查是否没有匹配所有元素 (一个也不匹配返回true,一个或一个以上返回false)
* 4.findFirst ———— 返回第一个元素
* 5.findAny ———— 返回当前流中的任意一个元素
* 6.count ———— 返回流中元素的总个数
* 7.max ———— 返回流中最大值
* 8.min ———— 返回流中最小值
*/
@Test
public void test9() {
boolean b1 = emps.stream().allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println("allMatch -> " + b1);
boolean b2 = emps.stream().anyMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println("anyMatch -> " + b2);
boolean b3 = emps.stream().noneMatch(e -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println("noneMatch -> " + b3);
Optional<Employee> op = emps.stream().sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())).findFirst();
Employee employee1 = op.get();
System.out.println("findFirst get() -> " + employee1);
Optional<Employee> op2 = emps.stream().filter((e) -> e.getStatus().equals(Employee.Status.BUSY)).findAny();
Employee employee2 = op2.get();
System.out.println("findAny get() -> " + employee2);
// 并行流 findAny
Optional<Employee> op22 = emps.parallelStream().filter((e) -> e.getStatus().equals(Employee.Status.BUSY)).findAny();
Employee e22 = op22.get();
System.out.println("并行流 findAny get() -> " + e22);
long count = emps.stream().count();
System.out.println("count -> " + count);
Optional<Employee> maxOptional = emps.stream().max((e1, e2) -> e1.getSalary().compareTo(e2.getSalary()));
Employee employee3 = maxOptional.get();
System.out.println("max get() -> " + employee3);
Optional<Double> maxOptional2 = emps.stream().map(Employee::getSalary).max((sa1, sa2) -> Double.compare(sa1,sa2));
Double maxSalary = maxOptional2.get();
System.out.println("max get() value -> " + maxSalary);
Optional<Double> minOptional = emps.stream().map(Employee::getSalary).min(Double::compare);
Double minSalary = minOptional.get();
System.out.println("min get() value -> " + minSalary);
}
// ---------------------------------终止操作 规约---------------------------------
/**
* 规约
* reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ———— 可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test10() {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
/**
* T reduce(T identity, BinaryOperator<T> accumulator) 使用提供的身份值和 associative累积功能对此流的元素执行 reduction ,并返回减小的值
* 此处先将 0 赋值给x,y从集合中取出第一个数作为自己的值,即1,0+1=1;计算完后x的值为计算结果1,y继续从集合中取出第二个元素作为自己的值,即2,1+2=3;
* x的值为3,y为4,3+4=7;x为7,y为5,7+5=12,x为12.....,依此计算下去即可得到结果 55
*/
Integer sum = list.stream().reduce(0, (x, y) -> x + y); // 计算和
System.out.println(sum);
System.out.println("-------------------------------");
/**
* Optional<T> reduce(BinaryOperator<T> accumulator) 使用 associative累积函数对此流的元素执行 reduction ,并返回描述减小值的 Optional (如果有)。
* 注:结果有可能为空的都被封装成 Optional 对象
*/
Optional<Double> reduce = emps.stream().map(Employee::getSalary).reduce(Double::sum); // 计算工资总和
System.out.println(reduce.get());
}
// ---------------------------------终止操作 收集---------------------------------
/**
* 收集
* collect ———— 将流转换成为其他形式。接收一个Collector接口的实现,用于给Stream中元素左汇总的方法
*/
@Test
public void test11() {
// 收集成 List
List<String> nameList = emps.stream()
.map(Employee::getName)
.collect(Collectors.toList());
System.out.println(nameList.toString());
// 收集成 Set
System.out.println("----------------");
Set<String> nameSet = emps.stream().map(Employee::getName).collect(Collectors.toSet());
System.out.println(nameSet.toString());
// 收集成其他集合
System.out.println("----------------");
HashSet<String> nameHashSet = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
System.out.println(nameHashSet);
}
@Test
public void test12() {
// 总数
Long count = emps.stream().collect(Collectors.counting());
System.out.println(count);
System.out.println("---------------------------");
// 平均值
Double salaryAvg = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println("salaryAvg = " + salaryAvg);
System.out.println("---------------------------");
// 总和
DoubleSummaryStatistics salarySum = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println("salarySum = " + salarySum);
System.out.println("---------------------");
// 最大值
Optional<Employee> max = emps.stream().collect(Collectors.maxBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
System.out.println("max[Employee] = " + max.get());
// 最小值
Optional<Double> min = emps.stream().map(Employee::getSalary).collect(Collectors.minBy((e1, e2) -> Double.compare(e1, e2)));
System.out.println("min = " + min.get());
}
// 分组
@Test
public void test13() {
// 分组
Map<Employee.Status, List<Employee>> groupStatus = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));
for (Map.Entry<Employee.Status, List<Employee>> entry : groupStatus.entrySet()) {
System.out.println("entry = " + entry);
}
}
// 多级分组(多列分组)
@Test
public void test14() {
// 多级分组
Map<Employee.Status, Map<String, List<Employee>>> collect = emps.stream().collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() <= 35) {
return "青年";
} else if (e.getAge() <= 50) {
return "中年";
} else {
return "老年";
}
}))); // 先按状态再按年龄分,可以继续嵌套分下去
for (Map.Entry<Employee.Status, Map<String, List<Employee>>> entry : collect.entrySet()) {
System.out.println(entry);
}
}
// 分片(分区),也可以多级
@Test
public void test15() {
Map<Boolean, List<Employee>> collect = emps.stream().collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
for (Map.Entry<Boolean, List<Employee>> entry : collect.entrySet()) {
System.out.println(entry);
}
}
// 其他
// 汇总函数
@Test
public void test16() {
// 汇总函数
DoubleSummaryStatistics dss = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getCount()); // 总数
System.out.println(dss.getAverage()); // 平均值
System.out.println(dss.getMax()); // 最大值
System.out.println(dss.getMin()); // 最小值
System.out.println(dss.getSum()); // 总和
}
// 连接
@Test
public void test17() {
String collect1 = emps.stream().map(Employee::getName).collect(Collectors.joining());
String collect2 = emps.stream().map(Employee::getName).collect(Collectors.joining(","));
String collect3 = emps.stream().map(Employee::getName).collect(Collectors.joining(",","-----","========="));
System.out.println(collect1);
System.out.println(collect2);
System.out.println(collect3);
}
}
Employee:
public class Employee {
private String name;
private Integer age;
private Double salary;
private Status status;
public Employee() {
}
public Employee(String name, Integer age, Double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Employee(String name, Integer age, Double salary, Status status) {
this.name = name;
this.age = age;
this.salary = salary;
this.status = status;
}
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{" +
"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 Objects.equals(name, employee.name) &&
// Objects.equals(age, employee.age) &&
// Objects.equals(salary, employee.salary);
// }
//
// @Override
// public int hashCode() {
// return Objects.hash(name, age, salary);
// }
public enum Status {
FREE,
BUSY,
VOCATION;
}
}
5.10练习
import org.junit.Before;
import org.junit.Test;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 交易测试
* 1.找出2011年发生的所有交易,并按交易额排序(从低到高)
* 2.交易员都在哪些不同的城市工作过?
* 3.查找所有来自剑桥的交易员,并按姓名排序
* 4.返回所有交易员的姓名字符串,按字母顺序排序
* 5.有没有交易员是在米兰工作过的?
* 6.打印生活在剑桥的交易员的所有交易额
* 7.所有交易中,最高的交易额是多少
* 8.找到交易额最小的交易
*/
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() {
List<Transaction> collect = transactions.stream()
.filter((t) -> t.getYear() == 2011)
.sorted((x, y) -> Integer.compare(x.getValue(),y.getValue()))
.collect(Collectors.toList());
System.out.println(collect.toString());
}
// 2.交易员都在哪些不同的城市工作过?
@Test
public void test2() {
List<String> collect = transactions.stream()
.map((t) -> t.getTrader().getCity())
.distinct()
.collect(Collectors.toList());
System.out.println(collect);
}
// 3.查找所有来自剑桥的交易员,并按姓名排序
@Test
public void test3() {
List<Trader> cambridge = transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.distinct()
.map((t) -> t.getTrader())
.sorted((t1,t2) -> t1.getName().compareTo(t2.getName()))
.collect(Collectors.toList());
System.out.println(cambridge);
}
// 4.返回所有交易员的姓名字符串,按字母顺序排序
@Test
public void test4() {
List<String> collect1 = transactions.stream()
.map((t) -> t.getTrader().getName())
.sorted()
.collect(Collectors.toList());
System.out.println(collect1);
System.out.println("-----------------------");
String collect = transactions.stream()
.map((t) -> t.getTrader().getName())
.distinct()
.sorted()
.collect(Collectors.joining());
System.out.println(collect);
System.out.println("---------------------------");
String str = transactions.stream()
.map((t) -> t.getTrader().getName())
.sorted()
.reduce("", String::concat);
System.out.println(str);
System.out.println("-------------------------");
String collect2 = transactions.stream()
.map((t) -> t.getTrader().getName())
.flatMap(TestTransaction::filterCharacter)
.sorted((s1,s2) -> s1.compareToIgnoreCase(s2))
.collect(Collectors.joining());
System.out.println(collect2);
}
public static Stream<String> filterCharacter(String str) {
List<String> list = new ArrayList<>();
for (Character c : str.toCharArray()) {
list.add(c.toString());
}
return list.stream();
}
// 5.有没有交易员是在米兰工作过的?
@Test
public void test5() {
// List<Trader> milan = transactions.stream()
// .filter((t) -> t.getTrader().getCity().equals("Milan"))
// .map((t) -> t.getTrader())
// .distinct()
// .collect(Collectors.toList());
// System.out.println(milan.toString());
boolean hasMilan = transactions.stream()
.anyMatch((t) -> t.getTrader().getCity().equals("Milan"));
System.out.println(hasMilan);
}
// 6.打印生活在剑桥的交易员的所有交易额
@Test
public void test6() {
Double sum = transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.collect(Collectors.summingDouble(Transaction::getValue));
System.out.println(sum);
System.out.println("--------------------------");
DoubleSummaryStatistics cambridge1 = transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.collect(Collectors.summarizingDouble(Transaction::getValue));
System.out.println(cambridge1.getSum());
System.out.println("-------------------------");
Optional<Integer> cambridge = transactions.stream()
.filter((t) -> t.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);
System.out.println(cambridge.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> max = transactions.stream()
.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
System.out.println(max.toString());
}
}
/**
* 交易员类
*/
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 + '\'' +
'}';
}
}
/**
* 交易类
*/
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 +
'}';
}
}
6. Optional
**定义:**Optional 类 (java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在用 Optional 可以更好的表达这个概念;并且可以避免空指针异常
常用方法:
- Optional.of(T t):创建一个 Optional 实例
- Optional.empty(T t):创建一个空的 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
Optional.of(T t):
@Test
public void test01(){
Optional<Employee> op = Optional.of(new Employee());
Employee employee = op.get();
}
12345
Optional.empty(T t):
@Test
public void test02(){
Optional<Employee> op = Optional.empty();
Employee employee = op.get();
}
Optional.ofNullable(T t):
@Test
public void test03(){
Optional<Employee> op = Optional.ofNullable(new Employee());
Employee employee = op.get();
}
isPresent():
@Test
public void test03(){
Optional<Employee> op = Optional.ofNullable(new Employee());
if (op.isPresent()) {
Employee employee = op.get();
}
}
不再一一例举…
7. 接口
7.1 默认方法
public interface MyFun {
/**
* 接口中除了全局静态常量、抽象方法外,java8中还允许有默认方法和静态方法
*/
// 抽象方法,没有实现
void test();
// 使用default修改默认方法,有具体的实现
default String getName(){
return "libo";
}
default Integer getAge(){
return 22;
}
}
类优先原则:
接口默认方法的 "类优先" 原则: 若一个接口中定义了一个默认方法,而另一个父类或接口中有定义了一个同名的方法时, 1.选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。 2.接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突。
7.2 静态方法
public interface MyFun {
// 用 static 修改接口的静态方法,有具体实现
static void getAddr(){
System.out.println("addr");
}
static String Hello(){
return "Hello World";
}
}
8. Date / Time API
新时间日期 API
8.1 安全问题
传统的日期格式化:
@Test
public void test01(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Callable<Date> task = () -> sdf.parse("20200517");
ExecutorService pool = Executors.newFixedThreadPool(10);
ArrayList<Future<Date>> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(pool.submit(task));
}
for (Future<Date> future : result) {
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
pool.shutdown();
}
加锁:
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> df = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static Date convert(String source) throws ParseException{
return df.get().parse(source);
}
}
@Test
public void test02(){
Callable<Date> task = () -> DateFormatThreadLocal.convert("20200517");
ExecutorService pool = Executors.newFixedThreadPool(10);
ArrayList<Future<Date>> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(pool.submit(task));
}
for (Future<Date> future : result) {
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
pool.shutdown();
}
DateTimeFormatter:
@Test
public void test03(){
DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
Callable<LocalDate> task = () -> LocalDate.parse("20200517",dtf);
ExecutorService pool = Executors.newFixedThreadPool(10);
ArrayList<Future<LocalDate>> result = new ArrayList<>();
for (int i = 0; i < 10; i++) {
result.add(pool.submit(task));
}
for (Future<LocalDate> future : result) {
try {
System.out.println(future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
pool.shutdown();
}
8.2 本地时间 / 日期
ISO 标准:
常用方法:
方法名 | 返回值类型 | 解释 |
---|---|---|
now( ) | static LocalDateTime | 从默认时区的系统时钟获取当前日期 |
of(int year, int month, int dayOfMonth, int hour, int minute, int second) | static LocalDateTime | 从年,月,日,小时,分钟和秒获得 LocalDateTime的实例,将纳秒设置为零 |
plus(long amountToAdd, TemporalUnit unit) | LocalDateTime | 返回此日期时间的副本,并添加指定的数量 |
get(TemporalField field) | int | 从此日期时间获取指定字段的值为 int |
@Test:
@Test
public void test01(){
//获取当前时间日期 now
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);
//指定时间日期 of
LocalDateTime ldt2 = LocalDateTime.of(2020, 05, 17, 16, 24, 33);
System.out.println(ldt2);
//加 plus
LocalDateTime ldt3 = ldt2.plusYears(2);
System.out.println(ldt3);
//减 minus
LocalDateTime ldt4 = ldt2.minusMonths(3);
System.out.println(ldt4);
//获取指定的你年月日时分秒... get
System.out.println(ldt2.getDayOfYear());
System.out.println(ldt2.getHour());
System.out.println(ldt2.getSecond());
}
LocalDate / LocalTime 不再一一例举…
/**
* 1.LocalDate - 日期;
* LocalTime - 时间;
* LocalDateTime - 日期时间
* 三者使用方式相差无几
*/
@Test
public void test1() {
System.out.println("--------LocalDate-----------");
LocalDate ld = LocalDate.now();
System.out.println(ld); // 2021-02-17
System.out.println("---------LocalTime----------");
LocalTime lt = LocalTime.now();
System.out.println(lt); // 11:43:25.312
/**
* static LocalDateTime now() 从默认时区的系统时钟获取当前的日期时间。
*/
System.out.println("---------LocalDateTime----------");
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); // 2021-02-17T11:43:25.313
}
@Test
public void test2() {
/**
* static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second)
* 从年,月,日,小时,分钟和秒获得 LocalDateTime的实例,将纳秒设置为零。
*/
LocalDateTime of = LocalDateTime.of(2015, 11, 22, 8, 22, 56);
System.out.println(of);
}
@Test
public void test3() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println("当前时间:" + ldt);
/**
* LocalDateTime plusYears(long years)
* 返回这个 LocalDateTime的副本,其中指定的时间段以添加的年数表示
*/
LocalDateTime plusYear = ldt.plusYears(2);
System.out.println("添加年数后:" + plusYear);
/**
* LocalDateTime minusMonths(long months)
* 返回此 LocalDateTime的副本,指定的时间以月为单位减去。
*/
LocalDateTime minusMonths = ldt.minusMonths(2);
System.out.println("减少月数后:" + minusMonths);
System.out.println(ldt.getYear()); // 年
System.out.println(ldt.getMonth().getValue()); // 月
System.out.println(ldt.getMonthValue()); // 月
System.out.println(ldt.getDayOfMonth()); // 日
System.out.println(ldt.getDayOfWeek()); // 星期几,例如 WEDNESDAY,英文形式
System.out.println(ldt.getDayOfYear()); // 一年中的第几天
System.out.println(ldt.getHour()); // 时
System.out.println(ldt.getMinute()); // 分
System.out.println(ldt.getSecond()); // 秒
System.out.println(ldt.getNano()); // 纳秒
}
8.3 时间戳
Instant:以 Unix 元年 1970-01-01 00:00:00 到某个时间之间的毫秒值
@Test:
@Test
public void test02(){
// 默认获取 UTC 时区 (UTC:世界协调时间)
Instant ins1 = Instant.now();
System.out.println(ins1);
//带偏移量的时间日期 (如:UTC + 8)
OffsetDateTime odt1 = ins1.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt1);
//转换成对应的毫秒值
long milli1 = ins1.toEpochMilli();
System.out.println(milli1);
//构建时间戳
Instant ins2 = Instant.ofEpochSecond(60);
System.out.println(ins2);
}
/**
* 2.Instant : 时间戳 (以 Unix 元年(1970年1月1日0时0分0秒) 到某个时间之间的毫秒值)
*/
@Test
public void test4() {
Instant instant = Instant.now(); // 默认获取 UTC 时区 (与北京时间相差8小时)
System.out.println(instant); // 2021-02-17T04:17:23.690Z
OffsetDateTime odt = instant.atOffset(ZoneOffset.ofHours(8)); // 设置时区偏移量,此处为8小时
System.out.println("设置时区偏移量后:" + odt); // 2021-02-17T12:17:23.690+08:00
// 获取时间戳 (毫秒值)
System.out.println("时间戳(毫秒值):" + instant.toEpochMilli()); // 1613536154974
System.out.println("秒:" + instant.getEpochSecond()); // 1613536154
/**
* static Instant ofEpochMilli(long epochMilli)
* 获得的一个实例 Instant从1970-01-01T00划时代使用毫秒:00:00Z。
*/
Instant instant1 = Instant.ofEpochMilli(1613535867413L);
System.out.println("将时间戳转成Instant对象:" + instant1); // 2021-02-17T04:24:27.413Z
/**
* static Instant ofEpochSecond(long epochSecond)
* 使用从1970-01-01T00:00:00Z的时代开始的秒数获得一个 Instant的实例
*/
Instant instant2 = Instant.ofEpochSecond(1613536154);
Instant instant3 = Instant.ofEpochSecond(20);
System.out.println("将秒转成Instant对象1:" + instant2); // 2021-02-17T04:29:14Z
System.out.println("将秒转成Instant对象2:" + instant3); // 1970-01-01T00:00:20Z
}
8.4 时间 / 日期 差
- Duration:计算两个时间之间的间隔
- Period:计算两个日期之间的间隔
@Test:
@Test
public void test03(){
//计算两个时间之间的间隔 between
Instant ins1 = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Instant ins2 = Instant.now();
Duration dura1 = Duration.between(ins1, ins2);
System.out.println(dura1.getSeconds());
System.out.println(dura1.toMillis());
}
@Test
public void test04(){
LocalDate ld1 = LocalDate.of(2016, 9, 1);
LocalDate ld2 = LocalDate.now();
Period period = Period.between(ld1, ld2); // ISO 标准
System.out.println(period.getYears());
System.out.println(period.toTotalMonths());
}
/**
* Duration : 计算两个 "时间" 之间的间隔
* Period : 计算两个 "日期" 之间的间隔
*/
@Test
public void test5() {
Instant ins1 = Instant.now();
try {
Thread.sleep(1000); // 休眠一秒
} catch (InterruptedException e) {}
Instant ins2 = Instant.now();
/**
* static Duration between(Temporal startInclusive, Temporal endExclusive)
* 获取一个 Duration表示两个时间对象之间的持续时间。
*/
Duration duration = Duration.between(ins1, ins2);
System.out.println(duration);
System.out.println(duration.getSeconds()); // 获取秒
System.out.println(duration.toMillis()); // 获取毫秒
// duration.toDays(); // 天
// duration.toHours(); // 时
// duration.toMinutes(); // 分
System.out.println("--------------------------");
LocalTime lt1 = LocalTime.now();
try {
Thread.sleep(1000); // 休眠一秒
} catch (InterruptedException e) {}
LocalTime lt2 = LocalTime.now();
System.out.println(Duration.between(lt1,lt2).toMillis());
}
@Test
public void test6() {
LocalDate ld1 = LocalDate.of(2016, 1, 1);
LocalDate ld2 = LocalDate.now();
Period period = Period.between(ld1, ld2);
System.out.println(period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
}
8.5 时间校正器
操纵日期:
@Test:
@Test
public void test01(){
//TemporalAdjusters:时间校正器
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);
//指定日期时间中的 年 月 日 ...
LocalDateTime ldt2 = ldt1.withDayOfMonth(10);
System.out.println(ldt2);
//指定时间校正器
LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
//自定义时间校正器
LocalDateTime ldt5 = ldt1.with((ta) -> {
LocalDateTime ldt4 = (LocalDateTime) ta;
DayOfWeek dow1 = ldt4.getDayOfWeek();
if (dow1.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
} else if (dow1.equals(DayOfWeek.SATURDAY)) {
return ldt4.plusDays(2);
} else {
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
}
@Test
public void test7() {
LocalDateTime ldt = LocalDateTime.now();
System.out.println("当前时间:" + ldt);
// 月中的天指定为10
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2);
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); // 下个周日
System.out.println(ldt3);
// 自定义校正器,到下一个工作日
LocalDateTime ldt5 = 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.SUNDAY)) {
return ldt4.plusDays(2);
} else {
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
}
8.6 格式化
- DateTimeFormatter:格式化时间 / 日期
@Test
public void test01(){
//默认格式化
DateTimeFormatter dtf1 = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime ldt1 = LocalDateTime.now();
String str1 = ldt1.format(dtf1);
System.out.println(str1);
//自定义格式化 ofPattern
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt2 = LocalDateTime.now();
String str2 = ldt2.format(dtf2);
System.out.println(str2);
//解析
LocalDateTime newDate = ldt1.parse(str1, dtf1);
System.out.println(newDate);
}
@Test
public void test8() {
/**
* DateTimeFormatter : 格式化时间/日期
*/
// DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);
System.out.println(strDate);
System.out.println("-------------指定格式-----------------");
// DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String strDate2 = ldt.format(dtf2);
System.out.println(strDate2);
System.out.println("------------将指定格式后的日期时间解析回LocalDateTime-------------------");
LocalDateTime ldt2 = ldt.parse(strDate2, dtf2);
System.out.println(ldt2);
}
8.7 时区
- ZonedDate
- ZonedTime
- ZonedDateTime
@Test:
@Test
public void test02(){
//查看支持的时区
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
//指定时区
LocalDateTime ldt1 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
System.out.println(ldt1);
//在已构建好的日期时间上指定时区
LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
ZonedDateTime zdt1 = ldt2.atZone(ZoneId.of("Europe/Tallinn"));
System.out.println(zdt1);
}
一些转换:
@Test
public void test03(){
// Date 转 LocalDateTime
Date date = new Date();
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
// LocalDateTime 转 Date
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zdt = localDateTime.atZone(zoneId);
Date date = Date.from(zdt.toInstant());
// 原则:利用 时间戳Instant
}
/**
* ZonedDate
* ZonedTime
* ZonedDateTime
*/
@Test
public void test9() {
// 获取所有时区ID
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
}
@Test
public void test10() {
// 指定时区,不指定为系统时间
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
// LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai")); // 上海
System.out.println("指定时区:" + ldt); // 2021-02-17T09:56:18.074
LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Europe/Tallinn"));
System.out.println("带时区的时间:" + zdt); // 2021-02-17T09:56:18.077+02:00[Europe/Tallinn]
LocalDateTime ldt3 = LocalDateTime.now(ZoneId.of("GMT+8"));
ZonedDateTime zdt2 = ldt3.atZone(ZoneId.of("GMT+8"));
System.out.println("带时区的时间:" + zdt2); // 2021-02-17T16:08:42.182+08:00[GMT+08:00]
}
时区ID
Asia/Shanghai 中国上海
GMT+8 (GMT%2B8)
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
9. 注解
9.1 重复注解
定义注解:
@Repeatable(MyAnnotations.class) //指定容器类
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "Java 8";
}
定义容器:
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
@Test:
public class Test01 {
//重复注解
@Test
@MyAnnotation("Hello")
@MyAnnotation("World")
public void test01() throws NoSuchMethodException {
Class<Test01> clazz = Test01.class;
Method test01 = clazz.getMethod("test01");
MyAnnotation[] mas = test01.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation ma : mas) {
System.out.println(ma.value());
}
}
}
/**
* 重复注解与类型注解
*/
public class TestAnnotation {
@MyAnnotation("Hello") // 可以使用重复注解了
@MyAnnotation("World")
public void show() {
}
@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());
}
}
/**
* 输出:
* Hello
* World
*/
}
9.2 类型注解
Java 8 新增注解:新增ElementType.TYPE_USE 和ElementType.TYPE_PARAMETER(在Target上)
@Repeatable(MyAnnotations.class) // 指定容器,要用重复注解,必须指定容器
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER}) // TYPE_PARAMETER 和 TYPE_USE 为类型注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "atguigu";
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
/**
* 重复注解与类型注解
*/
public class TestAnnotation {
@MyAnnotation("Hello") // 可以使用重复注解了
@MyAnnotation("World")
public void show() {
}
@MyAnnotation("Hello") // 可以使用重复注解了
@MyAnnotation("World")
public void show2(@MyAnnotation("abc") String str) { // 注解类型
}
@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());
}
}
/**
* 输出
* Hello
* World
*/
}