• 2.lombok系列2:lombok注解详解


    转自:https://www.imooc.com/article/18157

    开篇

    看到第一篇《初识lombok》你可能意犹未尽,本文我们按照场景来介绍一下常用的注解。

    未特别说明,均标注在类级别。

    lombok.Data

    最常用的注解,编译时自动添加Setter、Getter、toString()、equals()和hashCode()。

     1 package com.pollyduan;
     2 
     3 import java.util.Date;
     4 
     5 import lombok.Data;
     6 
     7 @Data
     8 public class User {
     9     private Integer id;
    10     private String userName;
    11     private String password;
    12     private String email;
    13     private Integer age;
    14     private Date signupTime;
    15     public static void main(String[] args) {
    16            User user=new User();
    17            user.setId(1001);
    18            user.setUserName("pollyduan");
    19            user.setPassword("123456");
    20            user.setEmail("pollyduan@pollyduan.com");
    21            user.setAge(30);
    22            user.setSignupTime(new Date());
    23            System.out.println(user);
    24        System.out.println(user.getUserName());
    25        System.out.println(user.hashCode());
    26         }
    27 }

    使用场景:

    POJO类、hibernate的实体类、json或jaxb的实体类。

    lombok.Value

    如果我们需要一个不可变的对象类,那么就用该注解。它在编译是自动添加Getter、toString()、equals()、hashCode()以及一个全参的构造器。

    注:没有无参构造器。如果需要,自己添加一个,或者增加一个后面介绍的lombok.NoArgsConstructor注解。

     1 package com.pollyduan;
     2 
     3 import java.util.Date;
     4 
     5 import lombok.Value;
     6 
     7 @Value
     8 public class User {
     9     private Integer id;
    10     private String userName;
    11     private String password;
    12     private String email;
    13     private Integer age;
    14     private Date signupTime;
    15 
    16     public static void main(String[] args) {
    17         /*
    18          * User user=new User();//The constructor User() is undefined
    19          * user.setId(1001);//The method setId(int) is undefined for the type
    20          * User
    21          */
    22         User user = new User(1001, "pollyduan", "123456", "pollyduan@pollyduan.com", 30, new Date());
    23         System.out.println(user);
    24         System.out.println(user.getUserName());
    25         System.out.println(user.hashCode());
    26     }
    27 }

    如果自定义了自动生成的方法,以自己定义的为准。

    lombok.Builder

    它把我们的Bean类包装为一个构建者模式,编译时增加了一个Builder内部类和全字段的构造器。

    注:没有Getter、Setter、toString()。如需其他方法,可以自己实现或者配合其他注解。

     1 package com.pollyduan;
     2 
     3 import java.util.Date;
     4 
     5 import lombok.Builder;
     6 import lombok.Data;
     7 
     8 @Builder
     9 public class User {
    10     private Integer id;
    11     private String userName;
    12     private String password;
    13     private String email;
    14     private Integer age;
    15     private Date signupTime;
    16 
    17     public static void main(String[] args) {
    18         /*
    19          * User user=new User();//The constructor User() is undefined
    20          */
    21         User user = new User(1001, "pollyduan", "123456", "pollyduan@pollyduan.com", 30, new Date());
    22         //或者
    23         user=User.builder()
    24                 .age(30)
    25                 .userName("pollyduan")
    26                 .build();
    27         System.out.println(user);
    28     }
    29 }

    构造器注解

    提供了三个构造器注解,分别为:

    lombok.AllArgsConstructor 增加全参构造器

    lombok.NoArgsConstructor 增加无参构造

    lombok.RequiredArgsConstructor 增加必选参数构造器

    该注解可同时标注,以增加不同的构造器。

    可以使用access属性定制访问级别,如:”access = AccessLevel.PROTECTED”

    前两个比较简单,必选参数构造器需要配合 lombok.NonNull 注解使用,只有标记了 NonNull 注解的字段才会被纳入 RequiredArgsConstructor 构造器中。

     1 package com.pollyduan;
     2 
     3 import java.util.Date;
     4 
     5 import lombok.NonNull;
     6 import lombok.RequiredArgsConstructor;
     7 
     8 @RequiredArgsConstructor
     9 public class User {
    10     @NonNull
    11     private Integer id;
    12     @NonNull
    13     private String userName;
    14     @NonNull
    15     private String password;
    16     private String email;
    17     private Integer age;
    18     private Date signupTime;
    19 
    20     public static void main(String[] args) {
    21         /*
    22          * User user=new User();
    23          * User user = new User(1001, "pollyduan", "123456", "pollyduan@pollyduan.com", 30, new Date());
    24          * //The constructor User() is undefined
    25          */
    26         User user=new User(1001, "pollyduan", "123456");//ok
    27         System.out.println(user);
    28     }
    29 }

    定制单个方法

    lombok.ToString 这个简单,就是增加toString()方法。

    类似的还有:

    lombok.EqualsAndHashCode 增加equals() 和 hashCode()。

    lombok.Getter 增加Getter方法

    lombok.Setter 增加Setter方法

    lombok.Cleanup

    该注解的对象,如Stream对象,如果有close()方法,那么在该对象作用域离开时会自动关闭。

     1 package com.pollyduan;
     2 
     3 import lombok.Cleanup;
     4 
     5 public class MyStream {
     6     public void close() {
     7         System.out.println("close.");
     8     }
     9 
    10     public static void main(String[] args) {
    11         System.out.println("new a mystream object.");
    12         @Cleanup
    13         MyStream ms=new MyStream();
    14         System.out.println("bye.");
    15     //退出前会自动调用close()
    16     }
    17 }

    执行后输出:

    new a mystream object.

    bye.

    close.

    日志相关注解

    lombok提供了一组日志相关注解,标注的类会隐式的定一个了一个名为log的日志对象。如:

     1 package com.pollyduan;
     2 
     3 import lombok.extern.java.Log;
     4 
     5 @Log
     6 public class User {
     7     public static void main(String[] args) {
     8         System.out.println(log.getClass());
     9     log.info("app log.");
    10     }
    11 }

    输出:

    class java.util.logging.Logger

    五月 19, 2017 1:32:58 下午 com.pollyduan.User main

    信息: app log.

    该组注解包括:

     1 @CommonsLog
     2     Creates private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
     3 
     4 @JBossLog
     5     Creates private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
     6 
     7 @Log
     8     Creates private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
     9 
    10 @Log4j
    11     Creates private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
    12 
    13 @Log4j2
    14     Creates private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
    15 
    16 @Slf4j
    17     Creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
    18 
    19 @XSlf4j
    20     Creates private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

    注:常用的日志处理器都在,一般我们使用log4j或slf4j。

    没有logback,请使用slf4j代理logback。

    Getter(lazy=true) 懒加载

    如果Bean的一个字段的初始化是代价比较高的操作,比如加载大量的数据;同时这个字段并不是必定使用的。那么使用懒加载机制,可以保证节省资源。

    懒加载机制,是对象初始化时,该字段并不会真正的初始化;而是第一次访问该字段时才进行初始化字段的操作。

    一言不合贴代码:

     1 package com.pollyduan;
     2 
     3 import lombok.Data;
     4 import lombok.Getter;
     5 
     6 @Data
     7 public class GetterLazyExample {
     8     @Getter(lazy = true)
     9     private final int[] cached = expensive();
    10     private Integer id;
    11 
    12     private int[] expensive() {
    13         int[] result = new int[100];
    14         for (int i = 0; i < result.length; i++) {
    15             result[i] = i;
    16             System.out.println(i);
    17         }
    18         System.out.println("cached 初始化完成。");
    19         return result;
    20     }
    21     public static void main(String[] args) {
    22         GetterLazyExample obj=new GetterLazyExample();
    23         obj.setId(1001);
    24         System.out.println("打印id:"+obj.getId());
    25         System.out.println("cached 还没有初始化哟。");
    26         // obj.getCached();
    27     }
    28 }

    运行就会发现,cached这个字段并没有初始化,虽然看起来它是final的,并直接赋值使用expensive()进行初始化。

    打印id:1001 cached

    还没有初始化哟。

    
    
    
    

    打开obj.getCached();的注释,获取这个字段的值,你就会发现它真的初始化了。

    打印id:1001

    cached 还没有初始化哟。

    0 1 ... 97 98 99

    cached 初始化完成。

    Synchronized

    同步方法注解。添加了该注解的方法,其方法体都会自动包含在一个synchronize块中。如:

     1 package com.pollyduan;
     2 
     3 import java.util.concurrent.BlockingQueue;
     4 
     5 import lombok.AllArgsConstructor;
     6 import lombok.Synchronized;
     7 
     8 @AllArgsConstructor
     9 public class SynchronizedExample {
    10     private BlockingQueue<String> queue;
    11 
    12     @Synchronized("queue")
    13     public void sync1() throws Exception {
    14         System.out.println("sync1.");
    15     }
    16 
    17     @Synchronized("queue")
    18     public void sync2() throws Exception {
    19         System.out.println("sync2.");
    20     }
    21 
    22     @Synchronized
    23     public void sync3() throws Exception {
    24         System.out.println("sync3.");
    25     }
    26 }

    如果直接指定了value=queue,其中queue为类的一个成员,那么该方法使用该成员queue作为加锁对象,放在同步块中执行。那么本例中,sync1和sync2是互斥的,sync1没有执行完之前,sync2会被挂起,等待sync1执行完成之后才可以执行。

    sync3,没有指定注解属性,这时lombok会自动创建一个对象作为锁,这样的结果是sync3自身互斥,多线程中两个线程不能同时执行sync3方法。

    sync3等同于:

    1 private final Object $lock = new Object[0];//lombok添加的
    2 public void sync3() throws Exception {
    3     synchronized($lock){
    4         System.out.println("sync3.");
    5     }
    6 }

    注:因为sync3与sync1使用的不是同一个锁,那么他们没有互斥关系,sync2也一样。

    一定要理清楚锁的关系,否则不要轻易使用该注解。

    SneakyThrows 隐藏异常

    自动捕获检查异常。

    我们知道,java对于检查异常,需要在编码时进行捕获,或者throws抛出。

    该注解的作用是将检查异常包装为运行时异常,那么编码时就无需处理异常了。

    提示:不过这并不是友好的编码方式,因为你编写的api的使用者,不能显式的获知需要处理检查异常。

     1 package com.pollyduan;
     2 
     3 import java.io.FileInputStream;
     4 import java.io.FileNotFoundException;
     5 import java.io.UnsupportedEncodingException;
     6 
     7 import lombok.SneakyThrows;
     8 
     9 public class SneakyThrowsExample {
    10     @SneakyThrows({UnsupportedEncodingException.class})
    11     public void test(byte[] bytes) {
    12         String str = new String(bytes, "UTF8");
    13     }
    14     @SneakyThrows({UnsupportedEncodingException.class,FileNotFoundException.class})
    15     public void test2(byte[] bytes) {
    16         FileInputStream file=new FileInputStream("no_texists.txt");
    17         String str=new String(bytes, "UTF8");
    18     }
    19     @SneakyThrows
    20     public void test3(byte[] bytes) {
    21         FileInputStream file=new FileInputStream("no_texists.txt");
    22         String str=new String(bytes, "UTF8");
    23     }
    24 
    25 }

    注解接受一个class数组的value属性,如果未指定value属性,默认捕获所有异常。

    以上代码相当于:

     1 package com.pollyduan;
     2 
     3 import java.io.FileInputStream;
     4 import java.io.FileNotFoundException;
     5 import java.io.UnsupportedEncodingException;
     6 
     7 import lombok.SneakyThrows;
     8 
     9 public class SneakyThrowsExample {
    10     public void test(byte[] bytes) {
    11         try {
    12             String str = new String(bytes, "UTF8");
    13         } catch (UnsupportedEncodingException e) {
    14             e.printStackTrace();
    15         }
    16     }
    17     public void test2(byte[] bytes) {
    18         try {
    19             FileInputStream file=new FileInputStream("no_texists.txt");
    20         } catch (FileNotFoundException e) {
    21             e.printStackTrace();
    22         }
    23         try {
    24             String str=new String(bytes, "UTF8");
    25         } catch (UnsupportedEncodingException e) {
    26             e.printStackTrace();
    27         }
    28     }
    29     public void test3(byte[] bytes) {
    30         try {
    31             FileInputStream file=new FileInputStream("no_texists.txt");
    32             String str=new String(bytes, "UTF8");
    33         } catch (Throwable e) {
    34             e.printStackTrace();
    35         }
    36     }
    37 
    38 }

    注:个人建议,了解即可,非必要不要使用。隐藏了异常细节,你的使用者会骂死你。

    辅助注解

    lombok.NonNull

    前面已经使用过了,标记在字段上,表示非空字段。

    也可以标注在方法参数上,会在第一次使用该参数是判断是否为空。

  • 相关阅读:
    【洛谷 P1896】[SCOI2005]互不侵犯(状压dp)
    【洛谷 P4289】[HAOI2008]移动玩具(搜索)
    【洛谷 SP283】NAPTIME
    【洛谷 P4342】[IOI1998]Polygon(DP)
    【洛谷 SP2878】Knights of the Round Table(双联通分量)
    【洛谷 P4168】[Violet]蒲公英(分块)
    【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)
    数学总结
    个人码风
    【洛谷 P3304】[SDOI2013]直径(树的直径)
  • 原文地址:https://www.cnblogs.com/sharpest/p/7888942.html
Copyright © 2020-2023  润新知