1、简介
- 速度更快
- 代码更少(增加了新的语法Lambda表达式)
- 强大的Stream API
- 便于并行
- 最大化减少空指针异常 Optional
其中最为核心的为Lambda表达式与Stream API
2、Lambda表达式
为什么使用Lambda表达式
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码
像数据一样进行传递)。
可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
复制代码
从匿名类到 Lambda 的转换
public class TestLambda {
@Test
public void test1() {
Runnable r1=new Runnable() {
@Override
public void run() {
System.out.println("hello Lambda");
}
};
r1.run();
Runnable r2=()->System.out.println("hello Lambda");
r2.run();
}
@Test
public void test2() {
TreeSet<String> ts1=new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
});
TreeSet<String> ts2=new TreeSet<>((o1,o2)->Integer.compare(o1.length(), o2.length()));
}
}
复制代码
Lambda表达式的基本语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda 操作符或剪头操作符。
它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的所有参数
右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
复制代码
语法格式一:无参,无返回值,Lambda体只有一条语句
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello World!" + num);
}
};
Runnable runnable = () -> System.out.println("Hello Lambda!");
复制代码
语法格式二:有一个参数时,无返回值,Lambda体只有一条语句
Consumer consumer=new Consumer() {
@Override
public void accept(Object o) {
System.out.println(o);
}
};
Consumer consumer=(o)-> System.out.println(o);
复制代码
语法格式三:有一个参数时,参数的小括号可以省略,无返回值,Lambda体只有一条语句
Consumer<String> consumer = x -> System.out.println(x);
复制代码
语法格式四:有两个及两个以上参数,有返回值,并且Lambda体中有多条语句
Comparator<Integer> comparator=new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
Comparator<Integer> c=(o1,o2)->{
System.out.println("函数式接口");
return Integer.compare(o1,o2);
};
复制代码
语法格式五:若Lambda体中只有一条语句,return和大括号都可以省略不写
Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
复制代码
语法格式六:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出数据类型,即"类型推断"
Comparator<Integer> comparator = (Integer x, Integer y) -> Integer.compare(x, y);
复制代码
3、函数式接口
什么是函数式接口?
- lambda表达式需要“函数式接口”的支持
- 接口中只有一个抽象方法的接口,成为函数式接口
- 可以使用Lambda 表达式来创建该接口的对象
- 可以在任意函数式接口上使用 @FunctionalInterface 注解,
这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包
含一条声明,说明这个接口是一个函数式接口。
自定义函数式接口
@FunctionalInterface
public interface MyNumber {
public double getValue();
}
复制代码
函数式接口中使用泛型
@FunctionalInterface
public interface MyFunc<T> {
public T getValue(T t);
}
复制代码
作为参数传递Lambda表达式:
为了将Lambda表达式作为参数传递,接收Lambda表达式的参数类型必须是与该Lambda表达式兼容的函数式接口的类型一致。
复制代码
public class MyTest {
public void test1() {
String newStr=toUpperString((str)->str.toUpperCase(), "abcdef");
}
public String toUpperString(MyFunc<String> mf,String str) {
return mf.getValue(str);
}
}
复制代码
java内置四大核心函数及其应用
1、Consumer:消费型接口,参数类型T,返回类型void,方法accept(T t)
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
@Test
public void test1() {
happy(10000,(m)->System.out.println(m));
}
public void happy(double money,Consumer<Double> consumer) {
consumer.accept(money);
}
复制代码
2、Supplier:供给型接口,没有参数,返回类型T,方法get()
@FunctionalInterface
public interface Supplier<T> {
T get();
}
@Test
public void test2() {
List<Integer> numList=getNumList(10, ()->(int)(Math.random()*100));
for(Integer num:numList) {
System.out.println(num);
}
}
public List<Integer> getNumList(int num,Supplier<Integer> supplier){
List<Integer> list=new ArrayList<>();
for(int i=0;i<num;i++) {
Integer n=supplier.get();
list.add(n);
}
return list;
}
复制代码
3、Function<T, R>:函数型接口,参数类型T,返回类型R,方法apply(T t)
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
@Test
public void test3() {
String newStr=strHandler("\t\t\t bjlemon",(str)->str.trim());
System.out.println(newStr);
newStr=strHandler("bjlemon",(str)->str.substring(2, 5));
System.out.println(newStr);
}
public String strHandler(String str,Function<String, String> function) {
return function.apply(str);
}
复制代码
4、Predicate:断言型接口,参数类型T,返回类型boolean,方法test(T t)
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
@Test
public void test4() {
List<String> list=Arrays.asList("Hello","bjlemon","Lambda","www","ok");
List<String> strList=filterStr(list,(s)->s.length()>3);
for(String str:strList) {
System.out.println(str);
}
}
public List<String> filterStr(List<String> list,Predicate<String> predicate){
List<String> strList=new ArrayList<>();
for(String str:list) {
if(predicate.test(str)) {
strList.add(str);
}
}
return strList;
}
复制代码
4、方法引用与构造器引用
方法的引用
当要传递给Lambda体的操作,已经有方法提供了实现,可以使用方法引用
(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)
实现抽象方法的参数列表,必须与方法引用的参数列表保持一致
方法引用:使用操作符::,将方法名和对象或类的名字分隔开来
注意:
方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致!
若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName
复制代码
public class TestMethodRef {
@Test
public void test1(){
Consumer<String> con = (str) -> System.out.println(str);
con.accept("Hello World!");
System.out.println("--------------------------------");
Consumer<String> con2 = System.out::println;
con2.accept("Hello Java8!");
}
@Test
public void test2() {
Employee emp = new Employee(101, "张三", 18, 9999.99);
Supplier<String> sup = () -> emp.getName();
System.out.println(sup.get());
System.out.println("----------------------------------");
Supplier<String> sup2 = emp::getName;
System.out.println(sup2.get());
}
@Test
public void test3() {
BiFunction<Double, Double, Double> fun = (x, y) -> Math.max(x, y);
System.out.println(fun.apply(1.5, 22.2));
System.out.println("--------------------------------------------------");
BiFunction<Double, Double, Double> fun2 = Math::max;
System.out.println(fun2.apply(1.2, 1.5));
}
@Test
public void test4() {
Comparator<Integer> com1 = (x, y) -> Integer.compare(x, y);
System.out.println("-------------------------------------");
Comparator<Integer> com2 = Integer::compare;
}
@Test
public void test5() {
BiPredicate<String, String> bp = (x, y) -> x.equals(y);
System.out.println(bp.test("abcde", "abcde"));
System.out.println("-----------------------------------------");
BiPredicate<String, String> bp2 = String::equals;
System.out.println(bp2.test("abc", "abc"));
System.out.println("-----------------------------------------");
Function<Employee, String> fun1 = (e) -> e.show();
System.out.println(fun1.apply(new Employee()));
System.out.println("-----------------------------------------");
Function<Employee, String> fun2 = Employee::show;
System.out.println(fun2.apply(new Employee()));
}
}
复制代码
构造器的引用
构造器的参数列表,需要与函数式接口中参数列表保持一致!
格式:ClassName::new
复制代码
public class TestMethodRef {
@Test
public void test6() {
Supplier<Employee> sup = () -> new Employee();
System.out.println(sup.get());
System.out.println("------------------------------------");
Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get());
}
@Test
public void test7() {
Function<String, Employee> fun1=(name)->new Employee(name);
System.out.println(fun1.apply("青子"));
Function<String, Employee> fun2 = Employee::new;
System.out.println(fun2.apply("青子"));
System.out.println("---------------------------------");
BiFunction<String, Integer, Employee> fun3=(name,age)->new Employee(name,age);
System.out.println(fun3.apply("青子",16));
BiFunction<String, Integer, Employee> fun4 = Employee::new;
System.out.println(fun4.apply("青子",16));
}
@Test
public void test8() {
Function<Integer, String[]> fun1 = (args) -> new String[args];
String[] strs1 = fun1.apply(10);
System.out.println(strs1.length);
Function<Integer, String[]> fun2 =String[]::new;
String[] strs2 = fun2.apply(15);
System.out.println(strs2.length);
System.out.println("--------------------------");
Function<Integer, Employee[]> fun3 = (args)->new Employee[args];
Employee[] emps1 = fun3.apply(20);
System.out.println(emps1.length);
Function<Integer, Employee[]> fun4 = Employee[]::new;
Employee[] emps2 = fun4.apply(30);
System.out.println(emps2.length);
}
}
复制代码
5、Stream API
简介
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作
使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。
可以使用 Stream API 来并行执行操作
简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式
复制代码
什么是Stream?
流(Stream)到底是什么呢?是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
集合讲的是数据,流讲的是计算!
注意:
Stream 自己不会存储元素
Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream
Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行
复制代码
Stream操作的三个步骤
- 创建Stream:一个数据源(如:集合、数组),获取一个流
public class TestStreamaAPI {
@Test
public void test1(){
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Stream<String> parallelStream = list.parallelStream();
Integer[] nums = new Integer[10];
Stream<Integer> stream1 = Arrays.stream(nums);
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
}
}
复制代码
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,
否则中间操作不会执行任何的处理!
而在终止操作时一次性全部处理,称为“惰性求值”。
public class TestStreamaAPI {
List<Employee> emps = Arrays.asList(
new Employee(101, "张三", 18, 9999.99),
new Employee(102, "李四", 58, 5555.55),
new Employee(103, "王五", 26, 3333.33),
new Employee(104, "赵六", 8, 7777.77),
new Employee(105, "田七", 12, 8888.88),
);
@Test
public void test2(){
Stream<Employee> stream = emps.stream()
.filter((e) -> {
System.out.println("测试中间操作");
return e.getAge() > 35;
});
stream.forEach(System.out::println);
}
@Test
public void test3(){
Iterator<Employee> it = emps.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
@Test
public void test4(){
emps.stream()
.filter((e) -> {
System.out.println("短路!");
return e.getSalary() > 5000;
}).limit(2)
.forEach(System.out::println);
}
@Test
public void test5(){
emps.stream()
.filter((e) -> e.getSalary() > 5000)
.skip(2)
.forEach(System.out::println);
}
@Test
public void test6(){
emps.stream()
.distinct()
.forEach(System.out::println);
}
@Test
public void test7(){
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);
Stream<Stream<Character>> stream=list.stream()
.map(LambdaTest::filterCharacter);
stream.forEach((sm)->{
sm.forEach(System.out::print);
});
System.out.println("--------------------------");
Stream<Character> sm=list.stream()
.flatMap(LambdaTest::filterCharacter);
sm.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();
}
@Test
public void test8(){
List<String> list= Arrays.asList("aaa","bbb","ccc","ddd","eee");
list.stream()
.sorted()
.forEach(System.out::println);
System.out.println("-------------------------");
employees.stream()
.sorted((e1,e2)->{
if(e1.getAge()==e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else{
return Integer.compare(e1.getAge(),e2.getAge());
}
}).forEach(System.out::println);
}
}
复制代码
- 终止操作(终端操作):一个终止操作,执行中间操作链,并产生结果
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。
public class TestStreamaAPI {
@Test
public void test1(){
boolean bl = emps.stream()
.allMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl);
boolean bl1 = emps.stream()
.anyMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl1);
boolean bl2 = emps.stream()
.noneMatch((e) -> e.getStatus().equals(Status.BUSY));
System.out.println(bl2);
}
@Test
public void test2(){
Optional<Employee> op = emps.stream()
.sorted((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
System.out.println(op.get());
System.out.println("--------------------------------");
Optional<Employee> op2 = emps.parallelStream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.findAny();
System.out.println(op2.get());
}
@Test
public void test3(){
long count = emps.stream()
.filter((e) -> e.getStatus().equals(Status.FREE))
.count();
System.out.println(count);
Optional<Double> op = emps.stream()
.map(Employee::getSalary)
.max(Double::compare);
System.out.println(op.get());
Optional<Employee> op2 = emps.stream()
.min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op2.get());
emps.stream().forEach(System.out::println);
}
@Test
public void test4(){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
System.out.println("----------------------------------------");
Optional<Double> op = emps.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(op.get());
}
}
复制代码
备注:map 和 reduce 的连接通常称为 map-reduce 模式,因 Google 用它来进行网络搜索而出名。
复制代码
6、接口中的默认方法与静态方法
Java8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,
默认方法使用 default 关键字修饰
复制代码
public interface MyFun {
default String getName(){
return "哈哈哈";
}
}
public interface MyInterface {
default String getName(){
return "呵呵呵";
}
public static void show(){
System.out.println("接口中的静态方法");
}
}
public class MyClass {
public String getName(){
return "嘿嘿嘿";
}
}
public class SubClass extends MyClass implements MyFun, MyInterface{
@Override
public String getName() {
return MyInterface.super.getName();
}
public static void main(String[] args) {
SubClass sc = new SubClass();
System.out.println(sc.getName());
MyInterface.show();
}
}
复制代码
接口默认方法的”类优先”原则:若一个接口中定义了一个默认方法,而另外一个父类或接口中又定义了一个同名的方法时
1、选择父类中的方法:如果一个父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
2、接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否是默认方法),
那么必须覆盖该方法来解决冲突
复制代码
7、新时间日期API
旧时间日期的线程安全性问题
public class TestSimpleDateFormat {
public void test1()throws Exception{
SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMdd");
Callable<Date> task=new Callable<Date>() {
@Override
public Date call() throws Exception {
return sdf.parse("20190120");
}
};
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();
}
}
复制代码
改进方案
复制代码
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> threadLocal=new ThreadLocal<DateFormat>(){
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date convert(String source)throws Exception{
return threadLocal.get().parse(source);
}
}
public class TestSimpleDateFormat {
@Test
public void test1()throws Exception{
Callable<Date> task=new Callable<Date>() {
@Override
public Date call() throws Exception {
return DateFormatThreadLocal.convert("20190120");
}
};
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();
}
}
复制代码
新时间日期类线程安全
public class TestSimpleDateFormat {
@Test
public void test2()throws Exception{
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task=new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20190120",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
LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象,
分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法
复制代码
public class TestLocalDateTime {
@Test
public void test1(){
LocalDateTime localDateTime=LocalDateTime.now();
System.out.println(localDateTime);
localDateTime=LocalDateTime.of(2019,01,20,20,00,01);
System.out.println(localDateTime);
localDateTime=localDateTime.plusYears(1);
System.out.println(localDateTime);
localDateTime=localDateTime.minusYears(2);
System.out.println(localDateTime);
System.out.println(localDateTime.getYear());
System.out.println(localDateTime.getMonthValue());
System.out.println(localDateTime.getDayOfMonth());
System.out.println(localDateTime.getHour());
System.out.println(localDateTime.getMinute());
System.out.println(localDateTime.getSecond());
}
@Test
public void test2(){
Instant instant=Instant.now();
System.out.println(instant);
OffsetDateTime odt=instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);
}
@Test
public void test3(){
Instant ins1 = Instant.now();
System.out.println("--------------------");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
Instant ins2 = Instant.now();
System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));
System.out.println("----------------------------------");
LocalDate ld1 = LocalDate.now();
LocalDate ld2 = LocalDate.of(2011, 1, 1);
Period pe = Period.between(ld2, ld1);
System.out.println(pe.getYears());
System.out.println(pe.getMonths());
System.out.println(pe.getDays());
}
@Test
public void test4(){
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 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 test5(){
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);
System.out.println(strDate);
LocalDateTime newLdt = ldt.parse(strDate, dtf);
System.out.println(newLdt);
}
@Test
public void test6(){
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
}
@Test
public void test7(){
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));
System.out.println(zdt);
}
}
复制代码
8、Optional 类
Optional<T> 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,
现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
复制代码
public class TestOptional {
@Test
public void test1(){
Optional<Employee> optional0=Optional.of(new Employee());
System.out.println(optional0.get());
Optional optional2=Optional.empty();
Optional<Employee> optional3=Optional.ofNullable(new Employee());
System.out.println(optional3.get());
Optional<Employee> optional4=Optional.ofNullable(null);
if(optional4.isPresent()){
System.out.println(optional4.get());
}
Employee employee=optional4.orElse(new Employee(1,"张三",18,888.88));
Employee employee1=optional4.orElseGet(()->new Employee());
Optional<Employee> optional5=Optional.ofNullable(new Employee(1,"张三",18,888.88));
Optional<String> str=optional5.map(Employee::getName);
Optional<String> str2=optional5.flatMap((e)->Optional.of(e.getName()));
}
}
复制代码
9、注解
JDK内置的基本注解类型
@Override: 限定重写父类方法, 该注释只能用于方法
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时
@SuppressWarnings: 抑制编译器警告
复制代码
JDK的元Annotation
用于修饰Annotation
@Retention:指定注解的生命周期
@Target:指定注解可以用在哪些地方
@Documented:指定注解是否被javadoc工具提取成文档
@Inherited:指定注解是否具有继承性
复制代码
自定义注解
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationDemo {
String value();
}
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "default";
String[] datas() default {"zhangsan", "lisi", "wangwu"};
Gender gender() default Gender.MALE;
AnnotationDemo annotationDemo() default @AnnotationDemo("annotation");
}
@MyAnnotation(
value = "张三",
datas = {"abc","ABC"},
gender = Gender.FEMALE,
annotationDemo = @AnnotationDemo(value = "xxx")
)
public class Demo {}
public class TestAnnotation {
@Test
public void test1() {
MyAnnotation myAnnotation = null;
if (Demo.class.isAnnotationPresent(MyAnnotation.class)) {
myAnnotation = Demo.class.getDeclaredAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.value());
System.out.println(Arrays.toString(myAnnotation.datas()));
System.out.println(myAnnotation.gender().name());
System.out.println(myAnnotation.annotationDemo().value());
}
}
}
复制代码
重复注解
@Repeatable(MyAnnotations.class)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "default";
}
@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("abc") String str)throws Exception{}
@Test
public void test()throws Exception{
Class<TestAnnotation> clazz=TestAnnotation.class;
Method method=clazz.getDeclaredMethod("show",String.class);
MyAnnotations ms=method.getDeclaredAnnotation(MyAnnotations.class);
for(MyAnnotation myAnnotation :ms.value()){
System.out.println(myAnnotation.value());
}
System.out.println("----------");
MyAnnotation[] myAnnotations=method.getDeclaredAnnotationsByType(MyAnnotation.class);
for(MyAnnotation m:myAnnotations){
System.out.println(m.value());
}
}
}
复制代码