一、 Lambda表达式
传统写法和使用lambda表达式的对比:
public class TestDemo {@Testpublic void test(){//比较Comparator<Integer> comparable=new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}};//lambda表达式比较Comparator<Integer> comparator=(x,y)-> Integer.compare(1,5);System.out.println(comparator);}//数据集合List<User> userList= Arrays.asList(new User("张三",18,5000),new User("李四",20,4000),new User("王五",46,2000),new User("小名",44,7000));//传统方式@Testpublic void test02(){//传统方式 遍历集合 通过判断将符合条件的数据过滤出来//假设过滤条件改变 需要动原有代码List<User> users=new ArrayList<>();for (User user : userList) {if (user.getAge()>18){users.add(user);}}for (User user : users) {System.out.println(users);}}@Test//优化方式1 策略模式public void UserTest1(){//传入过滤参数List<User> userList = getMyUserFilter(this.userList, new UserByAge());for (User user : userList) {System.out.println(user);}}// 策略模式public List<User> getMyUserFilter(List<User> list,MyUserFilter<User> mp){List<User> ageList=new ArrayList<>();for (User user : list) {if (mp.test(user)){ageList.add(user);}}return ageList;}//方式二 匿名内部类@Testpublic void test2(){List<User> List=getMyUserFilter(userList, new MyUserFilter<User>() {@Overridepublic boolean test(User t) {return t.getName().equals("张三");}});List.forEach(System.out::println);}//方式三 lambda表达式@Testpublic void test3(){List<User> myUserFilter = getMyUserFilter(userList, x -> x.getAge() > 18);myUserFilter.forEach(System.out::println);}//方式四 stream API@Testpublic void test4(){userList.stream().filter(x -> x.getAge() > 18).forEach(System.out::println);System.out.println("------------------------");userList.stream().map(User::getName).forEach(System.out::println);}}
MyUserFilter接口
public interface MyUserFilter<User> {boolean test(User t);}
实现接口
public class UserByAge implements MyUserFilter<User>{@Overridepublic boolean test(User t) {//过滤年龄18的userreturn t.getAge()>18;}}
- 可以看出来传统方式的处理,写的代码会比较繁琐和冗余。代码行数也比较多。
- lambda表达式更加灵活,大大的减少了代码编写行数。

二、Lmabda表达式的基础语法
- Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。它将
Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
语法格式一:无参数,无返回值。
public void test1(){Runnable runnable=new Runnable() {@Overridepublic void run() {System.out.println("123");}};runnable.run();System.out.println("----------------------------------------");//Lambda表达式Runnable runnable1=()-> System.out.println("123");runnable1.run();}
语法格式二:有参数,无返回值。
如果只有一个参数,可以省略小括号
@Testpublic void test2(){Consumer<String> consumer=(x)-> System.out.println(x);consumer.accept("123");---------------------------------Consumer<String> consumer= x-> System.out.println(x);consumer.accept("123");}
语法格式四:有两个以上参数,有返回值,并且lambda体中有多条语句。
注意:如果只有一条语句,大括号和return可以不写 ```java @Test public void test3(){ Comparator
comparator=(x,y)->{ System.out.println("函数式接口");return Integer.compare(x,y);
}; System.out.println(comparator.compare(5,8));
Comparator
integerComparator=(x,y)->Integer.compare(x,y); System.out.println(integerComparator.compare(10,5)); }
语法格式六:数据类型可以省略,因为可由编译器推断得出,称为“类型推断```javaConsumer<String> consumer=(String x)-> System.out.println(x);consumer.accept("123");Consumer<String> consumer=(x)-> System.out.println(x);consumer.accept("123");在接口前面中定义了数据类型,所以后面的参数可以省略掉数据类型。
总结:
左边和右边都只有一个参数,一条语句。 ()和{ }可以省掉
左边定义了类型,右边参数可以省类型。
三、java8四大内置函数式接口
- Consumer
:消费型接口 <br />

- Supplier
:供给型接口

- Function
:函数型接口

- Predicate
:断言型接口
四、方法引用的与构造器引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
(实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致!)
方法引用:使用操作符 “::” 将方法名和对象或类的名字分隔开来。
如下三种主要使用情况:
对象 :: 实例方法
User user=new User("试试",24,6000);Supplier<String> sup=()->user.getName();System.out.println(sup.get());System.out.println("---------------------------");Supplier<String> sup2=user::getName;System.out.println(sup2.get());
类 :: 静态方法
Comparator<Integer> comparable=( x, y)->Integer.compare(x, y);Comparator<Integer> comparator=Integer::compare;
类 :: 实例方法**
BiPredicate<String,String> biPredicate=(x,y)->x.equals(y);BiPredicate<String,String> bp=String::equals;boolean test = bp.test("12", "123");System.out.println(test);
构造器引用**
//无参构造Supplier<User> supplier=User::new;User user = supplier.get();System.out.println(user);//有参构造Function<String,User> userFunction=(x)->new User(x);User user1 = userFunction.apply("吱吱吱");System.out.println(user1);//有参构造2Function<String,User> userFunction1=User::new;User user2 = userFunction1.apply("啊啊啊");System.out.println(user2);
- 注意:
①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
五、Stream API
流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
流(Stream) 到底是什么呢?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意: **
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream创建方式
//1.可以通过Collection系列集合提供的stream()或者parallerStream()List<String> list=new ArrayList<>();Stream<String> stream = list.stream();//2.通过Arrays中的静态方法stream()获取User user[]=new User[10];Stream<User> stream1 = Arrays.stream(user);//3.通过Stream的静态of方法获取(底层还是Arrays的方法)Stream<String> stringStream = Stream.of("123", "675", "dasdsa", "gdf");//4.无限流方式 迭代Stream<Integer> iterate = Stream.iterate(0, x -> x + 2);iterate.limit(10).forEach(System.out::println);
中间操作
筛选与切片
- filter(Predicate p) 接收 Lambda , 从流中排除某些元素。
- distinct() 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
- limit(long maxSize) 截断流,使其元素不超过给定数量。
skip(long n) 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
//多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。@Testpublic void test3(){//中间操作;不会执行任何操作userList.stream().filter((x) ->{System.out.println("Stream API 的中间操作");return x.getSalary()>4000;}).limit(2).forEach(System.out::println);//终止操作:一次性执行全部内容,即‘堕性求值’// userStream.forEach(System.out::println);}
映射

public void mapTest(){userList.stream().map(user -> {System.out.println("给员工每人涨1000元!");return user.getSalary()+1000;}).forEach(System.out::println);System.out.println("---------------------------------");//map 接收一个函数作为参数,该函数会被应用到每个元//素上,并将其映射成一个新的元素。List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");Stream<Stream<Character>> streamStream = list.stream().map(TestStreamAPI::characterStream);streamStream.forEach(sm-> sm.forEach(System.out::println));System.out.println("---------------------------------");//flatmap 接收一个函数作为参数,将流中的每个值都换成另//一个流,然后把所有流连接成一个流Stream<Character> characterStream = list.stream().flatMap(TestStreamAPI::characterStream);characterStream.forEach(System.out::println);}
排序

@Testpublic void user(){List<String> list = Arrays.asList("eee", "bbb", "ccc", "ddd","aaa");//自然排序list.stream().sorted().forEach(System.out::println);System.out.println("--------------------------------------------");//自定义排序userList.stream().sorted((x1,x2)->{//按年龄排序return x1.getAge().equals(x2.getAge()) ? x1.getName().compareTo(x2.getName()):x1.getAge().compareTo(x2.getAge());}).forEach(System.out::println);}
终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的
值,例如:List、Integer,甚至是 void 。
```java
ListuserList= Arrays.asList( new User("张三",18,5000, Status.FREE),new User("李四",20,4000, Status.BUSY),new User("王五",46,2000, Status.VOCATION),new User("小名",44,7000, Status.FREE),new User("小红",16,2000, Status.BUSY),new User("李雷",33,10000, Status.FREE)
); //allMatch(Predicate p) 检查是否匹配所有元素 //anyMatch(Predicate p) 检查是否至少匹配一个元素 //noneMatch(Predicate p) 检查是否没有匹配所有元素 //findFirst() 返回第一个元素 //findAny() 返回当前流中的任意元素 // count() 返回流中元素总数 //max(Comparator c) 返回流中最大值 //min(Comparator c) 返回流中最小值 //forEach(Consumer c) 内部迭代(使用 Collection 接口需要用户去做迭 //代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了)
@Test public void test(){ //allMatch(Predicate p) 检查是否匹配所有元素 boolean b = userList.stream().anyMatch(user -> user.getStatus().equals(Status.BUSY)); System.out.println(b); //anyMatch(Predicate p) 检查是否至少匹配一个元素 //noneMatch(Predicate p) 检查是否没有匹配所有元素
//findFirst() 返回第一个元素 Optional
first = userList.stream().sorted((u1, u2) -> Integer.compare(u1.getSalary(), u2.getSalary())) .findFirst();
System.out.println(first.get());
//findAny() 返回当前流中的任意元素 Optional
first1 = userList.stream().filter(x -> x.getStatus().equals(Status.BUSY)).findFirst(); System.out.println(first1.get()); // count() 返回流中元素总数 //max(Comparator c) 返回流中最大值 Optional
max = userList.stream().max((u1, u2) -> Integer.compare(u1.getSalary(), u2.getSalary())); System.out.println(max.get()); } ```
归约

//reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。 返回@Testpublic void test01(){//获取所有员工的工资的和Optional<Integer> reduce = userList.stream().map(User::getSalary).reduce(Integer::sum);System.out.println(reduce.get());} //reduce(T iden, BinaryOperator b) 可以将流中元素反复结合起来,得到一个值。 返回@Testpublic void test01(){//获取所有员工的工资的和Optional<Integer> reduce = userList.stream().map(User::getSalary).reduce(Integer::sum);System.out.println(reduce.get());}

Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态
方法,可以方便地创建常见收集器实例,具体方法与实例如下表



// collect(Collector c) 将流转换为其他形式。接收一个 Collector接口的// 实现,用于给Stream中元素做汇总的方法@Testpublic void test02(){List<User> collect = userList.stream().filter((user) -> user.getSalary() > 2000).collect(Collectors.toList());collect.forEach(System.out::println);System.out.println("------------------------------------");//工资总数Long collect1 = userList.stream().collect(Collectors.counting());System.out.println(collect1);System.out.println("------------------------------------");//工资平均值Double collect2 = userList.stream().collect(Collectors.averagingDouble(User::getSalary));System.out.println(collect2);System.out.println("------------------------------------");//工资总和Double collect3 = userList.stream().collect(Collectors.summingDouble(User::getSalary));System.out.println(collect3);System.out.println("------------------------------------");//工资最大值Optional<User> collect4 = userList.stream().collect(Collectors.maxBy((x1, x2) -> Double.compare(x1.getSalary(), x2.getSalary())));System.out.println(collect4.get());System.out.println("------------------------------------");//工资最小值Optional<Integer> collect5 = userList.stream().map(User::getSalary).collect(Collectors.minBy((x1, x2) -> (int) Double.compare(x1, x2)));System.out.println(collect5.get());System.out.println("------------------------------------");//分组Map<Status, List<User>> collect6 = userList.stream().collect(Collectors.groupingBy(User::getStatus));collect6.forEach((k,v)-> System.out.println(k+" "+v));System.out.println("------------------------------------");//多级分组Map<Status, Map<String, List<User>>> collect7 = userList.stream().collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy((x) -> {if (x.getAge() > 20) {return "青年";} else if (x.getAge() > 60) {return "老年";} else {return "青少年";}})));collect7.forEach((k,v)->v.forEach((k2,v2)-> System.out.println(k+" "+k2+" "+v2)));}
并行流和串行流


Fork/Join 框架与传统线程池的区别
采用 “工作窃取”模式(work-stealing):当执行新的任务时它可以将其拆分分成更小的任务执行,并将小任务加到线
程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的
处理方式上.在一般的线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态.而在fork/join框架实现中,如果
某个子问题由于等待另外一个子问题的完成而无法继续运行.那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行.这种方式减少了线程
的等待时间,提高了性能.
public class ForkJoinCalculate extends RecursiveTask<Long> {private Long start;private Long end;//临界值private static final long THRESOLD=10000;public ForkJoinCalculate(Long start, Long end) {this.start = start;this.end = end;}@Overrideprotected Long compute() {//结束-开始Long length=end-start;//小于临界值用forif (length<=THRESOLD){long sum=0;for (long i = start; i <end ; i++) {sum+=i;}return sum;}else {//大于临界值 用ForkJoinlong middle=(start+end)/2;//左边 例: 0-5ForkJoinCalculate left=new ForkJoinCalculate(start,middle);left.fork();//右边 例: 6-10ForkJoinCalculate right=new ForkJoinCalculate(middle+1,end);right.fork();//连接总和return left.join()+right.join();}}}//测试代码//Fork Join框架@Testpublic void test(){Instant start = Instant.now();ForkJoinPool joinPool=new ForkJoinPool();ForkJoinTask<Long> task=new ForkJoinCalculate(0L,100000000L);Long sum = joinPool.invoke(task);Instant end = Instant.now();System.out.println("耗费时间:"+ Duration.between(start,end).toMillis());System.out.println(sum);}//stream并行流@Testpublic void test02(){long reduce = LongStream.rangeClosed(0, 1000000000L).parallel().reduce(0, Long::sum);}
- java8 StreamAPI并行流底层使用的是ForkJoin框架
- 处理大数据时比较有明显区别
Optional类

java8接口中的默认方法与静态方法


传统时间格式化的线程安全问题
package day02.com.atduigu.java8;importjava.text.SimpleDateFormat;import java.time.LocalDate;import java.time.format.DateTimeFormatter;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.*;public class TestSimpleDateFormat {publicstatic void main(String[] args) throws ExecutionException, Exception {/*Callable<Date> task = new Callable<Date>() {@Overridepublic Date call() throws Exception {return DateFormatThreadLocal.convert("20161218");}};ExecutorService pool = Executors.newFixedThreadPool(10);List<Future<Date>> results = new ArrayList<>();for(int i = 0; i < 10; i++) {results.add(pool.submit(task));}for(Future<Date> future : results){System.out.println(future.get());}pool.shutdown();*/DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");Callable<LocalDate> task = new Callable<LocalDate>() {@Overridepublic LocalDate call() throws Exception {return LocalDate.parse("20161218", dtf);}};ExecutorService pool = Executors.newFixedThreadPool(10);List<Future<LocalDate>> results = new ArrayList<>();for(int i = 0; i < 10; i++) {results.add(pool.submit(task));}for(Future<LocalDate> future : results){System.out.println(future.get());}pool.shutdown();}}packageday02.com.atduigu.java8;importjava.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class DateFormatThreadLocal {private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){@Override protectedDateFormat initialValue() {return new SimpleDateFormat("yyyyMMdd");}};public static Date convert(String source) throws ParseException {returndf.get().parse(source);}}
API-本地时间与时间戳
package day02.com.atduigu.java8;import org.junit.Test;import java.time.*;public class TestLocalDateTime {//3.//Duration:计算两个“时间”之间的间隔//Period:计算两个“日期之间的间隔”@Testpublic void tets4(){LocalDate ld1 = LocalDate.of(2015, 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());}@Testpublic void tets3(){Instant ins1 = Instant.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}Instant ins2 = Instant.now();Duration duration = Duration.between(ins1, ins2);System.out.println(duration.toMillis());System.out.println("-------------------------");LocalTime lt1 = LocalTime.now();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}LocalTime lt2 = LocalTime.now();System.out.println(Duration.between(lt1,lt2).toMillis());}//2. Instant : 时间戳(以Unix 元年:1970年1月1日 00:00:00 到某个时间之间的毫秒值)@Testpublic 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);}//1. LocalDate LocalTime LocalDateTime@Testpublic void test1(){LocalDateTime ldt = LocalDateTime.now();System.out.println(ldt);LocalDateTime ldt2 = LocalDateTime.of(2015, 10, 19, 13, 22, 33);System.out.println(ldt2);LocalDateTime ldt3 = ldt.plusYears(2);System.out.println(ldt3);LocalDateTime ldt4 = ldt.minusMonths(2);System.out.println(ldt4);System.out.println(ldt.getYear());System.out.println(ldt.getMonthValue());System.out.println(ldt.getDayOfMonth());System.out.println(ldt.getHour());System.out.println(ldt.getMinute());System.out.println(ldt.getSecond());}}
API-时间校正器

package day02.com.atduigu.java8;importorg.junit.Test;importjava.time.*;import java.time.temporal.Temporal;importjava.time.temporal.TemporalAdjuster;import java.time.temporal.TemporalAdjusters;public classTestLocalDateTime {//时间校正器@Testpublic void tett5(){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((l) -> {LocalDateTime ldt4 = (LocalDateTime) l;DayOfWeek daw = ldt4.getDayOfWeek();if(daw.equals(DayOfWeek.FRIDAY)) {return ldt4.plusDays(3);} else if (daw.equals(DayOfWeek.SATURDAY)) {return ldt4.plusDays(2);} else {return ldt4.plusDays(1);}});System.out.println(ldt5);}//3.//Duration:计算两个“时间”之间的间隔//Period:计算两个“日期之间的间隔”@Test public void tets4(){LocalDate ld1= LocalDate.of(2015, 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());}@Test public void tets3(){Instant ins1= Instant.now();try{Thread.sleep(1000);} catch(InterruptedException e) {e.printStackTrace();}Instant ins2 = Instant.now();Duration duration = Duration.between(ins1, ins2);System.out.println(duration.toMillis());System.out.println("-------------------------");LocalTime lt1 = LocalTime.now();try{Thread.sleep(1000);} catch(InterruptedException e) {e.printStackTrace();}LocalTime lt2 = LocalTime.now();System.out.println(Duration.between(lt1,lt2).toMillis());}//2. Instant : 时间戳(以Unix 元年:1970年1月1日 00:00:00 到某个时间之间的毫秒值)@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);}//1. LocalDate LocalTime LocalDateTime @Test public void test1(){LocalDateTime ldt = LocalDateTime.now();System.out.println(ldt);LocalDateTime ldt2 = LocalDateTime.of(2015, 10, 19, 13, 22, 33);System.out.println(ldt2);LocalDateTime ldt3 = ldt.plusYears(2);System.out.println(ldt3);LocalDateTime ldt4 = ldt.minusMonths(2);System.out.println(ldt4);System.out.println(ldt.getYear());System.out.println(ldt.getMonthValue());System.out.println(ldt.getDayOfMonth());System.out.println(ldt.getHour());System.out.println(ldt.getMinute());System.out.println(ldt.getSecond());}}
API-时间格式化与时区的处理

重复注解与类型注解

package day02.com.atduigu.java8;import java.lang.annotation.Repeatable;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.ElementType.CONSTRUCTOR;import static java.lang.annotation.ElementType.LOCAL_VARIABLE;@Repeatable(MyAnnotations.class)@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotation {String value() default "atguigu";}package day02.com.atduigu.java8;import java.lang.annotation.Repeatable;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.ElementType.CONSTRUCTOR;import static java.lang.annotation.ElementType.LOCAL_VARIABLE;@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})@Retention(RetentionPolicy.RUNTIME)public @interface MyAnnotations {MyAnnotation[] value();}package day02.com.atduigu.java8;import com.sun.istack.internal.NotNull;import org.junit.Test;import java.lang.reflect.Method;/*重复注解与类型注解*/public class TestAnnotation {//checker frameworkprivate @NotNull Object obj = null;@Testpublic void test1() throws Exception {Class<TestAnnotation> clazz = TestAnnotation.class;Method m1 = clazz.getMethod("show");MyAnnotation[] mas = m1.getAnnotationsByType(MyAnnotation.class);for (MyAnnotation myAnnotation: mas) {System.out.println(myAnnotation.value());}}@MyAnnotation("Hello")@MyAnnotation("World")public void show(@MyAnnotation("abc") String str){}}

