java Stream流

Stream流的的方法:迭代与排序、映射(map)
/*
     * 筛选切片
     * filter
     * limit
     * skip
     * distinct
     *  filter(Predicatep)接收Lambda ,从流中排除某些元素。
        distinct()筛选,通过流所生成元素的hashCode() 和equals() 去除重复元素
        limit(long maxSize)截断流,使其元素不超过给定数量。
        skip(long n)跳过元素,返回一个扔掉了前n 个元素的流。若流中元素不足n 个,则返回一个空流。与limit(n) 互补
     */
    List<Employee> emp=Arrays.asList(
            new Employee(0, "zhangsan",18,9999.99),
            new Employee(1,"lisi",20,999),
            new Employee(2,"wangwu",25,999),
            new Employee(3,"zhaoliu",20,8888)
            );

    //内部迭代:由Stream API完成
    @Test
    public void test1() {
        //中间操作
        Stream<Employee> s=emp.stream().filter((e)->{
            System.out.println("123456");
            return e.getAge()>35;
        });
        //终止操作:惰性求值
        s.forEach(System.out::println);
    }
    @Test
    public void test2() {
        emp.stream()
        .filter((e)-> {
            System.out.println("短路");//&& || 短路与
            return e.getAge()>35;
        })
        .limit(1)//找到满足的条件 1个  就停止
        .forEach(System.out::println);
    }
    /*
     *  map(Functionf)接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
        mapToDouble(ToDoubleFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的DoubleStream。
        mapToInt(ToIntFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的IntStream。
        mapToLong(ToLongFunction f)接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的LongStream。
        flatMap(Function f)接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
     */
    @Test
    public void test5() {
        List<String> list=Arrays.asList("aa","bb","cc","dd","ee");
        list.stream()
            .map((str) -> str.toUpperCase())
            .forEach(System.out::println);
        System.out.println("------------");
        emp.stream()
            .map(Employee::getName)
            .forEach(System.out::println);

        //将所有的流转为一个流{a,a,b,b,c,c}
        Stream<Character> sm=list.stream()
            .flatMap(TestStream2::filterCharacter);
        sm.forEach(System.out::println);
    }
    public static Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for(Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }
    //排序
    //自然排序sorted()
    //定制排序sorted(Comparator com)
    @Test
    public void test7() {
        List<String> list = Arrays.asList("ccc","bbb","aaa","ddd","ggg","eee");
        list.stream()
            .sorted()
            .forEach(System.out::println);
        System.out.println("----------------");

        emp.stream()
            .sorted((e1,e2) -> {
                if(e1.getAge()==e2.getAge()) {
                    return e1.getName().compareTo(e2.getName());
                }
                return 0;
            }).forEach(System.out::println);
    }
Stream流的方法:查找与匹配、归约(reduece)、收集、求总和、求平均、最大、最小、分组、多级分组、分区、连接。
List<Employee> emps = Arrays.asList(
        new Employee(0,"zhangsan",18,888.99,Status.FREE),
        new Employee(1,"lisi",20,8888.99,Status.BUSY),
        new Employee(2,"wangwu",18,8999.99,Status.VOCATION),
        new Employee(3,"zhaoliu",25,8899.99,Status.FREE),
        new Employee(4,"sunqi",34,10000.99,Status.FREE),
        new Employee(3,"zhaoliu",26,8899.99,Status.FREE),
        new Employee(4,"sunqi",55,10000.99,Status.FREE)
    );
    /*
     * 查找与匹配
     * allMatch --检查是否匹配所有的元素
     * anyMatch --至少有一个匹配
     * noneMatch --没有一个匹配
     * findFirst --返回第一个元素
     * count --元素个数
     * max 
     * min
     * 
     */
    @Test
    public void test1() {
        boolean b1 = emps.stream()
            .allMatch((e) -> e.getStatus().equals(Status.BUSY));
        System.out.println(b1);

        boolean b2=emps.stream()
            .anyMatch((e) -> e.getStatus().equals(Status.BUSY));
        System.out.println(b2);

        //排序,返回工资最低的
        Optional<Employee> op=emps.stream()
            .sorted((e1,e2) ->  Double.compare(e1.getSalary(),e2.getSalary()))
            .findFirst();
        System.out.println(op.get());

        //并行流,多线程执行
        Optional<Employee> op2=emps.parallelStream()
            .filter((e) -> e.getStatus().equals(Status.FREE))
            .findAny();
        System.out.println(op2.get());
    }

    @Test
    public void test2() {
        Long c1=emps.stream()
            .count();
        System.out.println(c1);
        //返回工资最高的 人
        Optional<Employee> op1=emps.stream()
            .max((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary()));
        System.out.println(op1.get());
        //返回最小的工资
        Optional<Double> op2=emps.stream()
            .map(Employee::getSalary)
            .min(Double::compare);
        System.out.println(op2.get());
    }

    /*
     * 归约
     * reduce()
     * 
     */
    @Test
    public void test3() {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        //将0作为x,取1作为y,x+y作为新的x,依次递归
        Integer sum = list.stream()
            .reduce(0,(x,y) -> x+y);
        System.out.println(sum);

        //总和可能为空,所以用optional  避免空指针异常
        Optional<Double> op=emps.stream()
            .map(Employee::getSalary)
            .reduce(Double::sum);
        System.out.println(op.get());
    }
    /*
     * 收集:取出所有的名字,放入集合中,若有重复的放入set
     * collect
     */
    @Test
    public void test4() {
        List<String> list=emps.stream()
            .map(Employee::getName)
            .collect(Collectors.toList());
        //遍历集合
        list.forEach(System.out::println);
        System.out.println("-----------------");
        //放入set
        Set<String> set=emps.stream()
            .map(Employee::getName)
            .collect(Collectors.toSet());
        set.forEach(System.out::println);
        System.out.println("=======================");
        //特殊的集合中的
        HashSet<String> hs=emps.stream()
            .map(Employee::getName)
            .collect(Collectors.toCollection(HashSet::new));

        hs.forEach(System.out::println);;
    }

    @Test
    public void test5() {
        //求总人数
        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> ep1=emps.stream()
            .collect(Collectors.maxBy((e1,e2) -> Double.compare(e1.getSalary(),e2.getSalary())));
        System.out.println("工资最高的员工"+ep1.get());
        //最小工资,先map映射到工资
        Optional<Double> op2=emps.stream()
            .map(Employee::getSalary)
            .collect(Collectors.minBy(Double::compare));
        System.out.println("工资最低是"+op2.get());
    }
    //分组
    @Test
    public void test6() {
        Map<Status,List<Employee>> m1 = emps.stream()
            .collect(Collectors.groupingBy(Employee::getStatus));
        //System.out.println(m1);

    }
    //多级分组
    @Test
    public void test7() {
        Map<Status,Map<String,List<Employee>>> map =emps.stream()
            .collect(Collectors.groupingBy(Employee::getStatus,Collectors.groupingBy((e) ->{
                //指定e的类型
                if(((Employee) e).getAge() <=35) {
                    return "青年";
                }else if(((Employee) e).getAge() <=50) {
                    return "中年";
                }else {
                    return "老年";
                }
            })));
        System.out.println(map);
    }
    //分区:满足条件的一个区,不满足条件的一个区
    @Test
    public void test8() {
        Map<Boolean,List<Employee>> map = emps.stream()
            .collect(Collectors.partitioningBy((e) ->e.getSalary()>8000));
        System.out.println(map);
    }
    //  DoubleSummaryStatistics 可以获取总数,平均值,最大值最小值
    @Test
    public void test9() {
        DoubleSummaryStatistics dss=emps.stream()
            .collect(Collectors.summarizingDouble(Employee::getSalary));
        System.out.println(dss.getSum());
        System.out.println(dss.getAverage());
        System.out.println(dss.getCount());
    }
    //连接成字符串
    @Test
    public void test10() {
        String str = emps.stream()
            .map(Employee::getName)
            .collect(Collectors.joining(","));
        System.out.println(str.toString());
    }
Stream Api
/**
 * 
 * @author Mr.zhang
 *
 */
public class TestStreamAPI1 {
    //创建Stream
    @Test
    public void test1() {
        //通过Collection
        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(10).forEach(System.out::println);;

    }
给定的数字列表,如何返回一个有每个数的平方构成的列表呢? 给定的【1,2,3,4,5】返回【1,4,9,16,25】
怎么样用map和reduce方法数一数流中有多少个Employee
/*
     * 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);
    }
    List<Employee> emps = Arrays.asList(
            new Employee(0,"zhangsan",18,888.99,Status.FREE),
            new Employee(1,"lisi",20,8888.99,Status.BUSY),
            new Employee(2,"wangwu",18,8999.99,Status.VOCATION),
            new Employee(3,"zhaoliu",25,8899.99,Status.FREE),
            new Employee(4,"sunqi",34,10000.99,Status.FREE),
            new Employee(3,"zhaoliu",26,8899.99,Status.FREE),
            new Employee(4,"sunqi",55,10000.99,Status.FREE)
        );
    /*
     * 2:怎么样用map和reduce方法数一数流中有多少个Employee
     * 
     */
    @Test
    public void test2() {
        Optional<Integer> count = emps.stream()
            .map((e) -> 1)
            .reduce(Integer::sum);
        System.out.println(count.get());
    }

Fork_Join工作窃取模式

需要继承RecursiveTask
public class ForkJoin extends RecursiveTask<Long> {

    /**Fork  Join  模式
     * 工作窃取
     */
    private static final long serialVersionUID = 1L;

    private long start;
    private long end;
    private static final long THRESHOLD =10000;
    public ForkJoin(long start , long end) {
        this.start = start;
        this.end  = end;
    }

    @Override
    protected Long compute() {
        long length = end - start;
        long sum = 0;

        if(length <= THRESHOLD) {
        for(long i =start; i<= end; i++) {
            sum+=i;

        }
        return sum;
        }
    else {
        long middle =(start + end)/2;
        ForkJoin left = new ForkJoin(start,middle);
        left.fork();//拆分子任务,同时压入线程队列
        ForkJoin right =new ForkJoin(middle+1,end);
        right.fork();
        return left.join() + right.join();
    }
    }
}
使用java8的并行流提高效率
public class TestForkJoin {

    @Test
    public void test1() {
        /**
         * java 8时间戳的使用
         * Fork Join 框架
         */
        Instant start = Instant.now();
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoin(0,10000000000L);
        Long sum = pool.invoke(task);
        System.out.println(sum);
        Instant end = Instant.now();
        //4109
        System.out.println("耗费时间:"+Duration.between(start, end).toMillis());
    }
    @Test
    public void test2() {
        long sum = 0L;
        Instant start = Instant.now();

        for(long i =0;i <=10000000000L; i++) {
            sum += i;
        }
        Instant end = Instant.now();
        System.out.println(sum);
        //3391
        System.out.println("耗费时间:"+Duration.between(start, end).toMillis());

    }
    /*
     * java8 并行流:parallel()
     *      顺序流:sequential()
     * 
     */
    @Test
    public void test3() {
        Instant start = Instant.now();
        LongStream.rangeClosed(0, 10000000000L)
            .parallel()
            .reduce(0,Long::sum);
        Instant end = Instant.now();
        //2910
        System.out.println("耗费时间:"+Duration.between(start, end).toMillis());
    }
}

java8 Optional<>避免空指针异常

实体类省略setter getter
public class Godness {
    private String name;
    //省略.....
}

public class Man {
    private Godness godness;
    //省略。。。。
}
public class NewMan {

    private Optional<Godness> godness = Optional.empty();
    //省略。。。。
}
Optional 容器类:用于尽量避免空指针异常
/*
     * 一、Optional 容器类:用于尽量避免空指针异常
     *  Optional.of(T t) : 创建一个 Optional 实例
     *  Optional.empty() : 创建一个空的 Optional 实例
     *  Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
     *  isPresent() : 判断是否包含值
     *  orElse(T t) :  如果调用对象包含值,返回该值,否则返回t
     *  orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
     *  map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
     *  flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
     */
    @Test
    public void test1() {
        Optional<Employee> op = Optional.of(new Employee());
        //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(1,"zhangsan",18,999.99,Status.BUSY));
        System.out.println(emp);
    }
    @Test
    public void test4() {
        Optional<Employee> op = Optional.ofNullable(null);
        Employee emp = op.orElseGet(() -> new Employee());
        System.out.println(emp);
    }
    @Test
    public void test5() {
        Optional<Employee> op = Optional.ofNullable(new Employee(1,"zhangsan",18,999.99,Status.BUSY));
        /*Optional<String> op2 = op.map((t) -> t.getName());
        Optional<U> java.util.Optional.map(Function<? super T, ? extends U> mapper)
        System.out.println(op2.get());*/


        //Optional<U> java.util.Optional.flatMap(Function<? super T, Optional<U>> mapper)
        //必须包装成Optional()
        Optional<String> op3 = op.flatMap((e) -> Optional.of(e.getName()));
        System.out.println(op3.get());
    }

    @Test
    public void test6() {
        Man man = new Man();
        String s = getGodnessName(man);
        System.out.println(s);
    }
    //需求:获取一个男人的女神的名字
    public String getGodnessName(Man man) {
        if(man != null) {
            Godness gn = man.getGodness();
            if(gn != null) {
                return gn.getName();
            }
        }
         return "苍老师";
    }
    public String getGodnessName2(Optional<NewMan> man) {
        return man.orElse(new NewMan())
                    .getGodness()
                    .orElse(new Godness("苍老师"))
                    .getName();
    }
    @Test
    public void test7() {
        //ofNullable() 构建对象
//      Optional<NewMan> op = Optional.ofNullable(null);
    /*  Optional<NewMan> op = Optional.ofNullable(new NewMan());
        Optional<NewMan> op2 = Optional.ofNullable(null);*/

        Optional<Godness> gn = Optional.ofNullable(new Godness("zhangsan"));
        Optional<NewMan> op2 = Optional.ofNullable(new NewMan(gn));

        String str = getGodnessName2(op2);
        System.out.println(str);
    }

java8 中允许接口中出现默认方法和静态方法

接口:
public interface MyFun {

    /**
     * java8 中允许接口中出现默认方法和静态方法
     * 
     */
    default String getName() {
        return "哈哈";
    }
    public static void show() {
        System.out.println("接口中的静态方法");
    }
}
public interface MyInterface {
    default String getName() {
        return "MyInterface";
    }
}
public class SubClass /*extends TestMyclass*/ implements MyFun,MyInterface {

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return MyFun.super.getName();
    }
/**
 * SubClass extends TestMyclass implements MyFun,MyInterface
 * 
 * SubClass 会实现 父类的同名方法
 */
}
public class TestMyclass {

    public String getName() {
        return "111222";
    }
}
优先执行父类中的方法,当注释父类,就近执行接口同名方法
public class TestDefaultInterface {

    public static void main(String[] args) {
        SubClass sc = new SubClass();
        System.out.println(sc.getName());

        MyFun.show();
    }
}

java8之前SimpleDateFormat 线程是不安全的

SimpleDateFormat 报错的解决方法

public class DateFormatThreadLoack {

    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
        protected DateFormat initialValue() {
            // SimpleDateFormat 线程单线程是不安全的 ,每次new 一个新的对象
            return new SimpleDateFormat("yyyyMMdd");
        }
    };

    public static Date covert(String source) throws ParseException {
        return df.get().parse(source);
    }
}

public class TestSimpleDateFormate {

    /**
     * 
     * @param args
     * @throws Exception
     * SimpleDateFormat 线程是不安全的 
     * 及解决方法  上锁
     * 
     */
    public static void main(String[] args) throws Exception{

        Callable<Date> task = new Callable<Date>() {

            @Override
            public Date call() throws Exception {
                // TODO Auto-generated method stub
                return DateFormatThreadLoack.covert("20171015");
            }
        };

        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();
    }
}
java8 时间的写法
public class TestNewDate {
    /**
     * 
     *java 8时间的使用
     * 
     */
    public static void main(String[] args) throws Exception{

        Callable<LocalDate> task = new Callable<LocalDate>() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");

            @Override
            public LocalDate call() throws Exception {
                return LocalDate.parse("20171015",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();
}
}

java 8本地时间,时间戳,时间校正器,时间格式化,时区处理

public class TestLocalDateTime {

    //1 LocalDate  LocalTime  LocalDateTime
    @Test
    public void test1() {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        LocalDateTime ldt2 = LocalDateTime.of(2017,12,12,10,9,8);
        System.out.println(ldt2);
        //ldt  加2年plusYears   减一个月 minusMoths(1)
        LocalDateTime ldt3 = ldt.plusYears(2);
        System.out.println(ldt3);
        System.out.println("--------");
        System.out.println(ldt.getYear());
        System.out.println(ldt.getMonthValue());
        System.out.println(ldt.getDayOfMonth());
        System.out.println(ldt.getHour());


    }

    //Instant :时间戳
    @Test
    public void test2() {
        Instant ins1 = Instant.now();//默认获取UTC时区
        System.out.println(ins1);

        OffsetDateTime odt = ins1.atOffset(ZoneOffset.ofHours(8));
        System.out.println(odt);
        //时间戳
        System.out.println(ins1.toEpochMilli());

        Instant ins2 = Instant.ofEpochSecond(60);
        System.out.println(ins2);
    }
    //Duration :计算两个时间的间隔
    //Period: 计算两个日期的间隔

    @Test
    public void test3() {
        Instant ins1 = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Instant ins2 = Instant.now();
        Duration duration = Duration.between(ins1, ins2);
        /*
         * 获取 s,ns:getSeconds()  getNano()
         * 获取ms :toMillis()
         */
        System.out.println(duration.toMillis());

        LocalTime ldt1 = LocalTime.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        LocalTime ldt2 = LocalTime.now();
        System.out.println(Duration.between(ldt1, ldt2).toMillis());

    }

    @Test
    public void test5(){
        LocalDate ld1 = LocalDate.of(2017, 1, 12);
        LocalDate ld2 = LocalDate.now();
        Period p = Period.between(ld1, ld2);
        System.out.println(p);
        System.out.println(p.getYears());
        System.out.println(p.getMonths());
        System.out.println(p.getDays());
    }
    /*
     * 时间校正器  TemporalAdjuster
     *  TemporalAdjusters
     */

    @Test
    public void test6() {
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);

        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((i) -> {
            LocalDateTime ldt4 = (LocalDateTime)i; 
            DayOfWeek dow = ldt4.getDayOfWeek();

            if(dow.equals(DayOfWeek.FRIDAY)) {
                return ldt4.plusDays(3);
            }else if(dow.equals(DayOfWeek.SATURDAY)) {
                return ldt4.plusDays(2);
            }else {
                return ldt4.plusDays(1);
            }
        });
        System.out.println(ldt5);
    }
    //格式化日期
    @Test
    public void test7() {
        DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
        LocalDateTime ldt = LocalDateTime.now();

        String str = ldt.format(dtf);
        System.out.println(str);
        System.out.println("-----------");

        DateTimeFormatter dt2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        String str2 = dt2.format(ldt);
        System.out.println(str2);

        //格式化日期转换回ISO标准
        LocalDateTime newDate = ldt.parse(str2, dt2);
        System.out.println(newDate);
    }

    //带时区的时间
    @Test
    public void test8() {
        Set<String> set = ZoneId .getAvailableZoneIds();
        //遍历set
        set.forEach(System.out::println);
    }

    @Test
    public void test9() {
        //其他时区此刻的时间
        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Monaco"));
        System.out.println(ldt);

        //带时区的此刻的当地时间
        LocalDateTime ldt2 = LocalDateTime.now(ZoneId.of("Europe/Monaco"));
        ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Europe/Monaco"));
        System.out.println(zdt);
    }
}

重复注解与类型注解

/**
 * 
 * @author Mr.zhang
 * 去@SuppressWarnings找头文件 
 */

@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE ,TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)//生命周期
public @interface MyAnnotation {

    String value() default "com";
}
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotations {

    MyAnnotation[] value();
}
/**
 * 重复注解与类型注解
 * @author Mr.zhang
 *
 */
public class TestAnnotation {
    //配合框架使用 checker framework
    private /*@NonNull*/ Object oj = null;

    @MyAnnotation("Hello")
    @MyAnnotation("World")
    public void show(@MyAnnotation("abc") String str) {

    }
    //反射
    @Test
    public void test1() throws NoSuchMethodException, SecurityException {
        Class<TestAnnotation> clazz = TestAnnotation.class;
        Method m1 = clazz.getMethod("show");
        MyAnnotation[] ma = m1.getAnnotationsByType(MyAnnotation.class);
        for (MyAnnotation myAnnotation : ma) {
            System.out.println(myAnnotation.value());
        }
    }
}