public class T1_Lambda {
@Test//原来的匿名内部类
public void test(){
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
}
//lambda表达式
@Test
public void testLambda(){
Comparator<Integer> comparator = (x , y) -> Integer.compare(x,y);
TreeSet treeSet = new TreeSet<>(comparator);
}
}
java类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private String name;
private Integer age;
private Double salary;
}
package com.jsxl.lambda;
import org.assertj.core.util.Lists;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class T2_Lambda {
List<Employee> employees = Arrays.asList(
new Employee("张三",22,999.99),
new Employee("张三",12,666.99),
new Employee("张三",23,888.99),
new Employee("张三",35,111.99),
new Employee("张三",24,333.99)
);
public List<Employee> filterEmployees(List<Employee> list){
List<Employee> emps = Lists.newArrayList();
for (Employee employee : list) {
if(employee.getAge() > 15){
emps.add(employee);
}
}
return emps;
}
@Test
public void filterEmployeesTest(){
List<Employee> list = filterEmployees(employees);
for (Employee employee : list) {
System.out.println(employee);
}
}
//优化方法
public List<Employee> filterEmployee(List<Employee> list ,MyPredicate<Employee> mp){
List<Employee> emps = Lists.newArrayList();
for (Employee employee : list) {
if(mp.test(employee)){
emps.add(employee);
}
}
return emps;
}
//优化方式一,策略设计模式
@Test
public void test1(){
List<Employee> list1 = filterEmployee(this.employees, new FilterEmployeeByAge());
for (Employee employee : list1) {
System.out.println(employee);
}
System.out.println("---------------------------");
List<Employee> list2 = filterEmployee(this.employees, new FilterEmployeeBySalary());
for (Employee employee : list2) {
System.out.println(employee);
}
}
//优化方式二,匿名内部类
@Test
public void test2(){
List<Employee> list = filterEmployee(this.employees, new MyPredicate<Employee>(){
@Override
public boolean test(Employee employee) {
return employee.getAge() >= 15;
}
});
for (Employee employee : list) {
System.out.println(employee);
}
}
//优化三 lambda表达式
@Test
public void test3(){
List<Employee> list = filterEmployee(this.employees,(e)-> e.getAge() >= 15);
list.forEach(System.out::println);
}
//优化四 StreamAPI
@Test
public void test4(){
employees.stream()
.filter((e -> e.getSalary() >= 777 ))
.limit(2)
.forEach(System.out::println);
employees.stream()
.map(Employee::getAge)
.forEach(System.out::println);
}
}
interface MyPredicate<T> {
boolean test(T t);
}
class FilterEmployeeByAge implements MyPredicate<Employee>{
@Override
public boolean test(Employee emp) {
return emp.getAge() >= 15;
}
}
class FilterEmployeeBySalary implements MyPredicate<Employee>{
@Override
public boolean test(Employee emp) {
return emp.getSalary() >= 777;
}
}
Java8中引入了一个新的操作符 | "->”该操作符称为箭头操作符或 Lambda 操作符 |
---|---|
箭头操作符将Lambda表达式拆分或两部分: | 左侧:Lambda表达式的参数列表,右侧:Lambda表达式中所需执行的功能,即 Lambda体 |
语法格式一:无参数,无返回值 | o -> System.out.println( "Hello Lambda! "); |
家语法格式二:有一个参数,并且无返回值 | ()->System.out.print1n(x) |
语法格式三:若只有一个参数,小括号可以省略不写 | x->System. out.print1n(x) |
语法格式四:有两个以上的参数,有返回值,并且 Lambda_体中有多条语句 | Comparator com = (x,y) ->fSystem.out-print1n("“函数式接口”);return Integer.compare(x, y); |
语法格式五:如果只有一条语句 | 大括号和return都可以不写 |
语法格式六:Lambda的参数列表的数据类型可以省略不写 | 因为JVM通过上下文推断出,数据类型,即“类型推断” |
package com.jsxl.lambda;
import org.assertj.core.util.Lists;
import org.junit.Test;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class T3_Lambda {
//无参无返回值
//()->System.out.println(x);
@Test
public void test1() {
int num = 0;//JDK1.7以前,必须是final
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!" + num); //num++报错
}
};
r.run();
System.out.println("-------------------");
Runnable r1 = () -> System.out.println("Hello World!");
}
// 有参数无返回值
//(x)->System.out.println(x);
@Test
public void test2() {
Consumer<String> consumer = (x) -> System.out.println(x);
consumer.accept("供给型接口");
}
// 有参数有返回值
@Test
public void test3() {
Comparator<Integer> com = (x,y) -> {
System.out.println("函数式接口");
return Integer.compare(x,y);
};
}
//如果只有一条语句大括号和return都可以不写
@Test
public void test4() {
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
}
//语法格式六:Lambda的参数列表的数据类型可以省略不写|因为JVM通过上下文推断出,数据类型,即“类型推断”
@Test
public void test5() {
// String[] strs;
// strs = {"aaa","bbb","ccc"};//报错
List<String> list = new ArrayList<>();//类型推断
show(new HashMap<>());//JDK1.7报错
}
public void show(Map<String,Integer> map){
}
}
函数式接口:接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解@FunctionalInterface
修饰
可以检查是否是函数式接口
1,调用Collections.sort()方法,通过定制排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda 作为参数传递。·
2,①声明函数式接口,接口中声明抽象方法,public String getvalue(String str);
②声明类 TestLambda ,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值。
③再将一个字符串的第2个和第4个索引位置进行截取子串。·
3,①声明一个带两个泛型的函数式接口,泛型类型为
②接口中声明对应抽象方法,
③在TestLambda类中声明方法,使用接口作为参数,计算两个 long型参数的和。
④再计算两个long型参数的乘积。·
package com.jsxl.lambda;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
interface MyFun{
Integer getValue(Integer integer);
}
interface MyFunction{
String getValue(String string);
}
interface MyFunction2<T,R>{
Long getValue(Long l1, Long l2);
}
public class T4_Lambda_Predicate {
List<Employee> employees = Arrays.asList(
new Employee("张三",22,999.99),
new Employee("张三",12,666.99),
new Employee("张三",23,888.99),
new Employee("张三",35,111.99),
new Employee("张三",24,333.99)
);
//对一个数进行运算
@Test
public void test1(){
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);
}
@Test
public void test2(){
Collections.sort(employees,(e1 ,e2)->{
if(e1.getAge() == e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else{
return -Integer.compare(e1.getAge(),e2.getAge());//负号控制升序降序
}
});
for (Employee employee : employees) {
System.out.println(employee);
}
}
@Test
public void test3(){
System.out.println(strHandler("\t函\t数\t式\t接\t口\t", str -> str.trim()));
System.out.println(strHandler("abcdef", e -> e.toUpperCase()));
}
//处理字符串
public String strHandler(String str , MyFunction mf){
return mf.getValue(str);
}
@Test
public void test4(){
operation(100L,200L,(x,y) -> x + y);
}
//对2个Long类型进行处理
public void operation(Long l1, Long l2 ,MyFunction2<Long, Long> mf){
System.out.println(mf.getValue(l1,l2));
}
}
函数式接口 | 举例 |
---|---|
Consumer :消费型接口 | void accept(T t); |
Supplier︰供给型接口 | T get(); |
Function |
Rapply(T t); |
Predicate ∶断言型接口 | boolean test(T t); |
package com.jsxl.lambda;
import org.assertj.core.util.Lists;
import org.junit.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;
public class T5_Lambda_Predicate {
//消费型接口 Consumer
@Test
public void test1(){
A(20,m -> System.out.println("她"+m+"岁了"));
}
public void A(double age, Consumer<Double> consumer){
consumer.accept(age);
}
//供给型接口 Supplier
@Test
public void test2(){
List<Integer> numList = getNumList(10, () -> (int) (Math.random() * 100));
numList.forEach(System.out::println);
}
//产生指定个数的整数,并放入集合中
public List<Integer> getNumList(Integer num, Supplier<Integer> supplier) {
List<Integer> list = Lists.newArrayList();
for (int i = 0; i < num; i++) {
Integer integer = supplier.get();
list.add(integer);
}
return list;
}
//函数型接口 Function
@Test
public void Test3(){
System.out.println(StrHandler("ABCDEF", (s) -> s.toLowerCase()));
}
//需求:用于处理字符串
public String StrHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
//断言型接口
@Test
public void test4(){
List<String> str = Arrays.asList("A", "BB", "CCC", "DDD");
filterStr( str , m -> m.length()>=3).forEach(System.out::println);
}
//需求满足需求的字符串放入集合中
public List<String> filterStr(List<String> str, Predicate<String> pre){
List<String> strList = Lists.newArrayList();
for (String s : str) {
if(pre.test(s)){
strList.add(s);
}
}
return strList;
}
}
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer< T >消费型接口 | T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) |
Supplier< T >供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get() ; |
Function |
T | R | 对类型为T的对象应用操作,并返回结果。结果是R类型的对象。包含方法:R apply(T t) ; |
Predicate< T >断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值。包含方法boolean test(T t); |
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
BiFunction |
T,U | R | 对类型为T,U参数应用操作,返回R类型的结果。包含方法为Rapply(T t,U u) ; |
UnaryOperator< T > (Function子接口) | T | T | 对类型为T的对象进行—元运算,并返回T类型的结果。包含方法为T apply(T t) ; |
BinaryOperator< T > (BiFunetion子接口) | T,T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(T t1,T t2) ; |
BiConsumer |
T,U | void | 对类型为T,U参数应用操作。包含方法为void accept(T t, U 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、类型的函数 |
方法励用:若Lambda体中的内容有方法已经实观了,我们可以使用"方法引用" |
---|
《可以理解为方法引用是Lambda表达式的另外一种表观形式》 |
主要有三种语法格式: |
对象::实例方法名 |
类:∵:静志方法名 |
卖:实侧方法名 |
package com.jsxl.lambda;
import org.junit.Test;
import java.io.PrintStream;
import java.util.Comparator;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class T6_Lambda_MethodRef {
//对象::实例方法名
@Test
public void test1(){
PrintStream ps = System.out;
Consumer<String> con1 = x -> ps.println(x);
Consumer<String> con2 = ps::println;
//con2等价于
Consumer<String> con3 = System.out::println;
con3.accept("对象::实例方法");
}
@Test
//Lambda中的泛型必须与返回值保持一致
public void test2(){
Employee emp = new Employee();
// Supplier supStr = () -> emp.getAge();
Supplier<Integer> supInt = () -> emp.getAge();
}
//类::静态方法名
@Test
public void test3(){
Comparator<Integer> com = (x, y) -> Integer.compare(x,y);
Comparator<Integer> com1 = Integer::compare;
System.out.println(com.compare(1, 2));
}
//源码:lambda体中的参数和返回值类型必须一致
// public static int compare(int x, int y){
// return (x < y) ? -1 : ((x == y) ? 0 : 1);
// }
//源码:函数式接口中的参数和返回值类型必须一致
// int compare(T o1, T o2);
//类::实例方法名
@Test
public void test4(){
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
BiPredicate<String, String> bp1 = String::equals;
System.out.println(bp1.test("1", "1"));
}
}
Lambda 体中调用方法的参数列表与返回值类型。要与函数式数式接口中抽象方法的函数列表和返回值类型保持一致
若Lambda参数列表中的第一参数是实创方法的调用者,而第二个参数鼍实创方法的参数时,可以使用ClassName :: method
注意:需要调用的构造器的参数列表要与的姓式接口中输象方法的参数列表保持一致!
package com.jsxl.lambda;
import org.junit.Test;
import java.util.function.Function;
import java.util.function.Supplier;
public class T7_Lambda_Construct {
//构造器引用
public void test1(){
Supplier<Employee> sup1 = () -> new Employee();
//构造器引用方式
Supplier<Employee> sup2 = Employee::new;
Employee employee = sup2.get();
System.out.println(employee);
}
@Test
public void test2(){
Function<String,Employee> fun1 = (x) -> new Employee(x);
Function<String,Employee> fun2 = Employee::new;
System.out.println(fun2.apply("csdn"));
}
@Test
public void test3(){
Function<Integer,String[]> fun1 = (x) -> new String[x];
System.out.println(fun1.apply(10).length);
Function<Integer,String[]> fun2 = String[]::new;
System.out.println(fun1.apply(20).length);
}
}
步骤 | - |
---|---|
创建Stream | 一个数据源(如:集合、数组),获取一个流 |
中间操作 | 一个中间操作链,对数据源的数据进行处理 |
终止操作(终端操作) | 一个终止操作,执行中间操作链,并产生结果 |
//创建Stream
@Test
public void test(){
//可以通过Collection 系列集合提供的stream() 或 parallelStream
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//通过Arrays 中静态方法 stream() 获取数组流
Employee[] emps = new Employee[10];
Stream<Employee> stream2 = Arrays.stream(emps);
//通过Stream 类中的静态方法of()
Stream<String> stream3 = Stream.of("aa", "bb", "cc");
//创建无限流 --迭代
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);
}
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理而在终止操作时一次性全部处理,称为“惰性求值”。
筛选与切片
方法 | 描述 |
---|---|
filter (Predicate p) | 接收Lambda ,从流中排除某些元素。 |
distinct) | 筛选,通过流所生成元素的hashCode()和l equals()去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量。 |
skip(long n) | 跳过元素,返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空流。与limit(n) 互补 |
内部迭代和惰性求值
List<Employee> employees = Arrays.asList(
new Employee("张三",22,999.99),
new Employee("张三",12,666.99),
new Employee("张三",23,888.99),
new Employee("张三",35,111.99),
new Employee("张三",24,333.99)
);
//中间操作
/*
筛选与切片
filter——接收Lambda ,从流中排除某些元素。
limit——截断流,使其元素不超过给定数量。
skip(n)—跳过元素,返回一个扔掉了前n个元素的流。若渣中元素不足n 个,则返回一个空流。与limit(n)互补
distinct—筛选,通过流所生成元素的 hashcode()和equals()去除重复元素
*/
//内部迭代:迭代操作由Stream API 完成
@Test
public void Test1(){
//中间操作不会执行任何操作
Stream<Employee> stream = employees.stream()
.filter(e -> {
System.out.println("Stream API 的中间操作");
return e.getAge() > 20;
});
//终止操作:一次性执行完全部内容,即“惰性求值”
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() > 444.44;
})
.limit(2)
.forEach(System.out::println);
}
skip跳过前2条
@Test//skip跳过前2条
public void test4() {
employees.stream()
.filter(e -> e.getSalary() > 444.44)
.skip(2)
.forEach(System.out::println);
}
distinct去重
// 重复对象去重制造2条相同数据 通过hashCode() 和 equals() 去除重复
// List employees = Arrays.asList(
// new Employee("张三",23,888.99),
// new Employee("张三",23,888.99),
// );
public void test4() {
employees.stream()
.filter(e -> e.getSalary() > 444.44)
.skip(2)
.distinct()//加上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(T1_streamApi::filterCharacter);//类::方法 的映射
//取值 Stream>
stream.forEach(sm -> sm.forEach(System.out::println));
System.out.println("-----flatMap---------");
Stream<Character> stream1 = list.stream()
.flatMap(T1_streamApi::filterCharacter);//{a,a,a,b,b,b...}
//取值
stream1.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str){
List<Character> list = Lists.newArrayList();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
// System.out.println(list);
return list.stream();
}
@Test
public void test6() {
List<String> list = Arrays.asList("aaa","bbb","ccc","ddd","eee");
List list1 = new ArrayList();
list1.add(11);
list1.add(22);
// list1.add(list);
list1.addAll(list);
// System.out.println("list1.add(list)"+list1);//[11, 22, [aaa, bbb, ccc, ddd, eee]]
System.out.println("list1.addAll(list)"+list1);//[11, 22, aaa, bbb, ccc, ddd, eee]
}
package com.jsxl.stream_api;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
@Data
@AllArgsConstructor
@NoArgsConstructor
class Employee {
private String name;
private Integer age;
private Double salary;
private Status status;
}
enum Status{
FREE,
BUSY,
VOCATION;
}
public class T2_StreamApi {
List<Employee> employees = Arrays.asList(
new Employee("张三",22,999.99, Status.FREE),
new Employee("赵四",12,666.99, Status.BUSY),
new Employee("王五",23,888.99, Status.VOCATION),
new Employee("赵六",23,777.99, Status.FREE),
new Employee("田七",35,111.99, Status.BUSY)
);
/*
查找与匹配
allMatch—检查是否匹配所有元素
anyMatch一经查是否至少匹配一个元素
noneMatch—检查是否没有匹配所有元素
findFirst——返回第一个元素
findAny—返回当流中的任意元素
count—返回流中元素的总个数
max——返国流中最大值
min——返回流中最小值
*/
@Test
public void test1() {
boolean b1 = employees.stream()
.allMatch(e -> e.getStatus().equals(Status.FREE));
System.out.println(b1);
boolean b2 = employees.stream()
.anyMatch(e -> e.getStatus().equals(Status.FREE));
System.out.println(b2);
boolean b3 = employees.stream()
.noneMatch(e -> e.getStatus().equals(Status.FREE));
System.out.println(b3);
//Optional 避免空指针异常
Optional<Employee> op = employees.stream()
.sorted((e1, e2) -> -Double.compare(e1.getSalary(),e2.getSalary()))
.findFirst();
System.out.println(op.get());
// Optional op2 = employees.stream()
// .filter(e -> e.getStatus().equals(Status.FREE))
// .findAny();
// System.out.println(op2.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::compare);
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);
}
方法 | 描述 |
---|---|
count | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min (Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用Collection接口需要用户去做迭代,称为外部迭代。相反,Stream API使用内部迭代——它帮你把迭代做了) |
归约 | - |
reduce(T iden,BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional |
备注:map和reduce的连接通常称为map-reduce模式,因Google用它来讲行网络搜索而出名。 | - |
方法 | 描述 |
---|---|
collect (Collector c) | 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Collector接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下代码:
终止操作
/*
收集
collect -- 将流转换为其他方式。接收一个Collector接口的实现
*/
@Test
public void test4() {
employees.stream()
.map(Employee::getName)
.collect(Collectors.toList())
.forEach(System.out::println);
System.out.println("-----------------------------");
employees.stream()
.map(Employee::getName)
.collect(Collectors.toSet())
.forEach(System.out::println);
System.out.println("-----------------------------");
employees.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(HashSet::new))
.forEach(System.out::println);
}
@Test
public void test5() {
//总数
System.out.println(employees.stream()
.collect(Collectors.counting()));
//平均值
System.out.println(employees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary)));
//总和
System.out.println(employees.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary)));
//最大值
System.out.println(employees.stream()
.collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()))));
//最小值
System.out.println(employees.stream()
.collect(Collectors.minBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()))));
}
//分组
@Test
public void test6() {
Map<Status, List<Employee>> map = employees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
//{FREE=[Employee(name=张三, age=22, salary=999.99, status=FREE), Employee(name=赵六, age=23, salary=777.99, status=FREE)], BUSY=[Employee(name=赵四, age=12, salary=666.99, status=BUSY), Employee(name=田七, age=35, salary=111.99, status=BUSY)], VOCATION=[Employee(name=王五, age=23, salary=888.99, status=VOCATION)]}
@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);
//{VOCATION={青年=[Employee(name=王五, age=23, salary=888.99, status=VOCATION)]}, FREE={青年=[Employee(name=张三, age=22, salary=999.99, status=FREE), Employee(name=赵六, age=23, salary=777.99, status=FREE)]}, BUSY={青年=[Employee(name=赵四, age=12, salary=666.99, status=BUSY), Employee(name=田七, age=35, salary=111.99, status=BUSY)]}}
}
//分区
@Test
public void test8() {
Map<Boolean, List<Employee>> map = employees.stream()
.collect(Collectors.partitioningBy(e -> e.getSalary() > 888.88));
System.out.println(map);
//{false=[Employee(name=赵四, age=12, salary=666.99, status=BUSY), Employee(name=赵六, age=23, salary=777.99, status=FREE), Employee(name=田七, age=35, salary=111.99, status=BUSY)], true=[Employee(name=张三, age=22, salary=999.99, status=FREE), Employee(name=王五, age=23, salary=888.99, status=VOCATION)]}
}
@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());
.collect(Collectors.joining(",","===","==="));
// System.out.println("collect(Collectors.joining())"+str);//张三赵四王五赵六田七
System.out.println("collect(Collectors.joining(\",\",\"===\",\"===\"))"+str);//===张三,赵四,王五,赵六,田七===
}
package com.jsxl.stream_api;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
public class T3_streamApi {
/*
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方法数一数流中有多少个Employee 呢?
*/
List<Employee> emps = Arrays.asList(
new Employee("张三", 22, 999.99, Status.FREE),
new Employee("赵四", 12, 666.99, Status.BUSY),
new Employee("王五", 23, 888.99, Status.VOCATION),
new Employee("赵六", 23, 777.99, Status.FREE),
new Employee("田七", 35, 111.99, Status.BUSY)
);
@Test
public void test2(){
Optional<Integer> count = emps.stream()
.map(e -> 1)
.reduce(Integer::sum);
System.out.println(count.get());
}
}
package com.jsxl.stream_api;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
//交易员类
@Data
@AllArgsConstructor
@NoArgsConstructor
class Trader {
private String name;
private String city;
}
//交易类
@Data
@AllArgsConstructor
@NoArgsConstructor
class Transaction {
private Trader trader;
private Integer year;
private Integer value;
}
public class T4_streamApi {
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, 100),
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)
.sorted((t1,t2) -> t1.getName().compareTo(t2.getName()))
.distinct()
.forEach(System.out::println);
}
//4.返回所有交易员的姓名字符串,按字母顺序排序
@Test
public void test4() {
transactions.stream()
.map(t -> t.getTrader().getName())
.sorted()
.forEach(System.out::println);
System.out.println("--------------------------");
System.out.println(transactions.stream()
.map(t -> t.getTrader().getName())
.sorted()
.reduce("", String::concat));
System.out.println("--------------------------");
transactions.stream()
.map(t -> t.getTrader().getName())
.flatMap(T4_streamApi::filterCharacter)
.sorted()
.forEach(System.out::print);
System.out.println();
System.out.println("--------------------------");
transactions.stream()
.map(t -> t.getTrader().getName())
.flatMap(T4_streamApi::filterCharacterString)
.sorted((s1,s2) -> s1.compareToIgnoreCase(s2))
.forEach(System.out::print);
}
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()){
list.add(ch);
}
return list.stream();
}
public static Stream<String> filterCharacterString(String str) {
List<String> list = new ArrayList<>();
for (Character ch : str.toCharArray()){
list.add(ch.toString());
}
return list.stream();
}
//5.有没有交易员是在米兰工作的?
@Test
public void test5() {
boolean flag = transactions.stream()
.anyMatch(t -> t.getTrader().getCity().equals("Milan"));
System.out.println(flag);
}
//6.打印生活在剑桥的交易员的所有交易额
@Test
public void test6() {
Optional<Integer> sum = transactions.stream()
.filter(e -> e.getTrader().getCity().equals("Cambridge"))
.map(Transaction::getValue)
.reduce(Integer::sum);//类::静态方法
System.out.println(sum.get());
}
//7.所有交易中,最高的交易额是多少
@Test
public void test7() {
System.out.println(transactions.stream()
.map(t -> t.getValue())
.max(Integer::max).get());
}
//8.找到交易额最小的交易
@Test
public void test8() {
System.out.println(transactions.stream()
.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue())));
}
}
Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总.
采用“工作窃取”模式(work-stealing) :
当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。
相对于一般的线程池实现, fork/join框架的优势体现在对其中包含的任务的处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程的等待时间,提高了性能.
package com.jsxl.stream_api;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.concurrent.RecursiveTask;
@AllArgsConstructor
public class ForkJoinCalculate extends RecursiveTask<Long> {
private static final long serialVersionUID = 134656970987L;
private long start;
private long end;
private static final long THRESHOLD = 10000;
@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 com.jsxl.stream_api;
import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ForkJoinPool;
public class TestForkJoin {
@Test
public void test1(){
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinCalculate task = new ForkJoinCalculate(0,10000000);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗时" + Duration.between(start,end).toMillis());
}
@Test
public void test2(){
Instant start = Instant.now();
long sum = 0L;
for (long i=0; i<10000000L;i++) {
sum+=i;
}
System.out.println(sum);
Instant end = Instant.now();
System.out.println("耗时" + Duration.between(start,end).toMillis());
}
}
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
Java 8 中将并行进行了优化,我们可以很容易的对数据进行并行操作。Stream API可以声明性地通过parallel() 与
sequential(在并行流与顺序流之间进行切换。
/*
java8 并行流
*/
@Test
public void test3(){
Instant start = Instant.now();
LongStream.rangeClosed(1,100000000000L)
.parallel()
.reduce(0,Long::sum);
Instant end = Instant.now();
System.out.println("耗时" + Duration.between(start,end).toMillis());//耗时8524
}
Optional 解决 返回全新实例(线程安全) LocalDate、 LocalTime、 LocalDateTime类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。 TemporalAdiuster :时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。 Java8中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime @SuppressWarnings() 从中获取元注解
常用方法
Optional.of(T t):创建一个 Optional 实例Optional.empty() :创建一个空的Optional实例
0ptional.ofNullable(T t):若 t 不为 null,创建0ptional实例,否则创建空实例isPresent() :判断是否包含值
orElse(T t) :如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s):如果调用对象包含值,返回该值,否则返回s获取的值
map(Function f):如果有值对其处理,并返回处理后的0ptional,否则返回Optional.empty()
flatMap(Function mapper):与map 类似,要求返回值必须是Optional
package com.jsxl.stream_api;
import org.junit.Test;
import java.util.Optional;
public class T5_Optional {
@Test
public void test1(){
Optional<Employee> op = Optional.of(null);
Employee emp = op.get();
System.out.println(emp);
}
@Test
public void test2(){
Optional<Employee> op = Optional.empty();
System.out.println(op.get());
}
@Test
public void test3(){
Optional<Employee> op = Optional.ofNullable(null);
// if(op.isPresent()){
// System.out.println(op.get());
// }
// Employee emp = op.orElse(new Employee("张三",18,888.88,Status.FREE));
// System.out.println(emp);
Employee emp1 = op.orElseGet(() -> new Employee());
System.out.println(emp1);
}
@Test
public void test4(){
Optional<Employee> op = Optional.ofNullable(new Employee("张三",18,888.88,Status.FREE));
// Optional
package com.jsxl.stream_api;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import java.util.Optional;
@Data
@AllArgsConstructor
@NoArgsConstructor
class Goodness {
private String Name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Man{
private String name;
private Goodness goodness;
}
class NewMan {
private Optional<Goodness> goodness = Optional.empty();
public NewMan() {
}
public NewMan(Optional<Goodness> goodness) {
this.goodness = goodness;
}
public Optional<Goodness> getGoodness() {
return goodness;
}
public void setGoodness(Optional<Goodness> goodness) {
this.goodness = goodness;
}
@Override
public String toString() {
return "NewMan{" +
"goodness=" + goodness +
'}';
}
}
public class T6_ForkJoin{
@Test
public void test1(){
Man man = new Man();
System.out.println(getGoodnessName(man));
Optional<Goodness> gn = Optional.ofNullable(new Goodness("自带对象"));
Optional<NewMan> op = Optional.ofNullable(new NewMan(gn));
// Optional
Java8新特性_接口中的默认方法与静态方法
public interface Myfun {
default String getName(){
return "java8 新特性Myfun";
}
}
public class MyClass {
public String getName(){
return "java8 新特性MyClass";
}
}
public interface MyInterface {
default String getName(){
return "java8 新特性MyInterface";
}
public static void show(){
System.out.println("接口中的静态方法");
}
}
2个接口都有这个方法,实现2这个2个接口的类必须实现这个方法
//public class SubClass extends MyClass implements Myfun {
//
//}
public class SubClass implements Myfun,MyInterface{//2个接口都有这个方法,实现2这个2个接口的类必须实现这个方法
@Override
public String getName() {
return Myfun.super.getName();
}
}
public class TestDefaultInterface {
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(subClass.getName());//类优先原则
MyInterface.show();
}
}
日期api存在问题
package com.jsxl.dateApi;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class T1_dateApi {
public static void main(String[] args) throws ExecutionException, InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = new Callable<Date>(){
@Override
public Date call() throws Exception {
return sdf.parse("20211123");
}
};
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();
}
}
package com.jsxl.dateApi;
import java.text.DateFormat;
import java.text.ParseException;
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.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class T2_DateApi {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
protected DateFormat initialValue(){
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date convert(String source) throws ParseException {
return df.get().parse(source);
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return T2_DateApi.convert("20211123");
}
};
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();//连接池记得关
}
}
package com.jsxl.dateApi;
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.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class T3_dateApi {
public static void main(String[] args) throws ExecutionException, InterruptedException {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task = new Callable<LocalDate>(){
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20211123",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();
}
}
使用LocalDate、LocalTime、 LocalDateTime
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法日期的操纵
TemporalAdjusters :该类通过静态方法提供了大量的常用TemporalAdjuster的实现。
例如获取下个周日:LocalDate nextSunday = LocalDate.now().with(
TemporalAdjusters.next(DayOfweek.SUNDAY)
);
package com.jsxl.dateApi;
import lombok.extern.log4j.Log4j;
import lombok.extern.log4j.Log4j2;
import org.junit.Test;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
@Log4j2
public class T4_dateApi {
//1.LocalDate LocalTime LocalDateTime
@Test
public void test1(){
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
LocalDateTime ldt2 = LocalDateTime.of(2021, 11, 23, 10, 37, 59);
System.out.println(ldt2);
log.info(ldt.plusYears(2));
log.info(ldt.minusMonths(2));
log.info(ldt.getYear());
log.info(ldt.getMonth());
log.info(ldt.getMonthValue());
log.info(ldt.getDayOfMonth());
log.info(ldt.getHour());
}
//Instant : 时间戳(以Unix 元年:1970年1月1日00:00:00到某个时间之间的毫秒值)
@Test
public void test2(){
Instant ins1 = Instant.now();//默认获取UTC时区
log.debug(ins1);
log.debug(ins1.atOffset(ZoneOffset.ofHours(8)));
log.debug(ins1.toEpochMilli());
log.debug(Instant.ofEpochSecond(60));
// 10:48:59.644 [main] DEBUG com.jsxl.dateApi.T4_dateApi - 2021-11-23T02:48:59.632Z
// 10:48:59.648 [main] DEBUG com.jsxl.dateApi.T4_dateApi - 2021-11-23T10:48:59.632+08:00
// 10:48:59.648 [main] DEBUG com.jsxl.dateApi.T4_dateApi - 1637635739632
// 10:48:59.648 [main] DEBUG com.jsxl.dateApi.T4_dateApi - 1970-01-01T00:01:00Z
}
//Duration:计算两个"时间"之间的间隔
@Test
public void test3(){
Instant ins1 = Instant.now();
try{
Thread.sleep(1000);
}catch (InterruptedException e){
}
Instant ins2 = Instant.now();
log.error(Duration.between(ins1,ins2).toMillis());
}
//Period:计算两个"日期"之间的间隔
@Test
public void test4(){
LocalDate last = LocalDate.of(2019, 12, 30);
LocalDate now = LocalDate.now();
Period period = Period.between(last, now);
log.warn(period);
log.warn(period.getYears());
log.warn(period.getMonths());
log.warn(period.getDays());
// 10:58:28.312 [main] WARN com.jsxl.dateApi.T4_dateApi - P1Y10M24D
// 10:58:28.316 [main] WARN com.jsxl.dateApi.T4_dateApi - 1
// 10:58:28.316 [main] WARN com.jsxl.dateApi.T4_dateApi - 10
// 10:58:28.316 [main] WARN com.jsxl.dateApi.T4_dateApi - 24
}
//TemporalAdjuster:时间矫正器
@Test
public void test5(){
LocalDateTime now = LocalDateTime.now();
log.fatal(now);
log.fatal(now.withDayOfMonth(10));
log.fatal(now.with(TemporalAdjusters.next(DayOfWeek.FRIDAY.FRIDAY)));
// 11:03:37.047 [main] ERROR com.jsxl.dateApi.T4_dateApi - 2021-11-23T11:03:37.043
// 11:03:37.051 [main] ERROR com.jsxl.dateApi.T4_dateApi - 2021-11-10T11:03:37.043
// 11:03:37.053 [main] ERROR com.jsxl.dateApi.T4_dateApi - 2021-11-26T11:03:37.043
//自定义下一个工作日
LocalDateTime nextWork =now.with( l -> {
LocalDateTime ldt = (LocalDateTime) l ;
DayOfWeek dow = ldt.getDayOfWeek();
if(dow.equals(DayOfWeek.FRIDAY)){
return ldt.plusDays(3);
}else if(dow.equals(DayOfWeek.THURSDAY)) {
return ldt.plusDays(4);
}else if(dow.equals(DayOfWeek.WEDNESDAY)) {
return ldt.plusDays(5);
}else if(dow.equals( DayOfWeek.TUESDAY)) {
return ldt.plusDays(6);
}else {
return ldt.plusDays(7);
}
});
log.fatal(nextWork);
}
//DateTimeFormatter:格式化时间日期
@Test
public void test6(){
DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE;
LocalDateTime now = LocalDateTime.now();
log.info(now.format(isoDate));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String format = dtf.format(now);
log.info(format);
log.info(now.parse(format,dtf));
// 11:17:05.131 [main] INFO com.jsxl.dateApi.T4_dateApi - 2021-11-23
// 11:17:05.134 [main] INFO com.jsxl.dateApi.T4_dateApi - 2021年11月23日 11:17:05
// 11:17:05.135 [main] INFO com.jsxl.dateApi.T4_dateApi - 2021-11-23T11:17:05
}
}
时区的处理
其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式例如:Asia/Shanghai 等
Zoneld:该类中包含了所有的时区信息
getAvailableZonelds():可以获取所有时区时区信息
of(id):用指定的时区信息获取Zoneld对象
package com.jsxl.dateApi;
import org.junit.Test;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;
public class T5_DateApi {
@Test
public void test1(){
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
}
@Test
public void test2(){
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
System.out.println(ldt);
ZonedDateTime zdt = ldt.atZone(ZoneId.of("Europe/Tallinn"));
System.out.println(zdt);
ZonedDateTime zdt1 = ldt.atZone(ZoneId.of("Europe/Isle_of_Man"));
System.out.println(zdt1);
// 2021-11-23T05:23:40.243
// 2021-11-23T05:23:40.243+02:00[Europe/Tallinn]
// 2021-11-23T05:23:40.243Z[Europe/Isle_of_Man]
}
}
重复注解和注解类型
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER})//注解类型需要加注解 TYPE_PARAMETER
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
String value() default "Annotation";
}
@Target({TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {
MyAnnotation[] value();
}
/*
重复注解和注解类型
*/
public class RepetitionAnnotation {
// checker framework
// private /*NonNull*/ Object obj = null;
@Test
public void test() throws Exception{
Class<RepetitionAnnotation> clazz = RepetitionAnnotation.class;
Method method = clazz.getMethod("show");
MyAnnotation[] mas = method.getAnnotationsByType(MyAnnotation.class);
for (MyAnnotation ma : mas) {
System.out.println(ma.value());
}
}
@MyAnnotation("Hello")
@MyAnnotation("World")
// public void show(@MyAnnotation("abc") String str){//注解类型
public void show(){
}
}