【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题(中)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【小家Java】Lombok的使用详解(最详尽的解释,覆盖讲解所有可用注解),解决@Builder.Default默认值问题(中)

@ToString/@EqualsAndHashCode


这两个注解也比较好理解,就是生成toString,equals和hashcode方法,同时后者还会生成一个canEqual方法,用于判断某个对象是否是当前类的实例。,生成方法时只会使用类中的非静态成员变量,这些都比较好理解。毕竟静态的东西并不属于对象本身


@ToString
public class Demo {
    private final int finalVal = 10;
    private transient String name = "aa";
    private int age;
}
 public static void main(String[] args) throws Exception {
        Demo demo = new Demo();
        System.out.println(demo); //Demo(finalVal=10, age=0)
    }


我们发现静态字段它是不输出的。

有些关键的属性,可以控制toString的输出,我们可以了解一下:


@ToString(
        includeFieldNames = true, //是否使用字段名
        exclude = {"name"}, //排除某些字段
        of = {"age"}, //只使用某些字段
        callSuper = true //是否让父类字段也参与 默认false
)


备注:大多数情况下,使用默认的即可,毕竟大多数情况都是POJO


@Generated:暂时貌似没什么用

@Getter/@Setter

这一对注解从名字上就很好理解,用在成员变量上面或者类上面,相当于为成员变量生成对应的get和set方法,同时还可以为生成的方法指定访问修饰符,当然,默认为public


这两个注解直接用在类上,可以为此类里的所有非静态成员变量生成对应的get和set方法。如果是final变量,那就只会有get方法


@Getter
@Setter
public class Demo {
    private final int finalVal = 10;
    private String name;
    private int age;
}


编译后:


public class Demo {
    private final int finalVal = 10;
    private String name;
    private int age;
    public Demo() {
    }
    public int getFinalVal() {
        Objects.requireNonNull(this);
        return 10;
    }
    public String getName() {
        return this.name;
    }
    public int getAge() {
        return this.age;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
}


@NonNull


这个注解可以用在成员方法或者构造方法的参数前面,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常。


//成员方法参数加上@NonNull注解
public String getName(@NonNull Person p){
    return p.getName();
}

编译后:

public String getName(@NonNull Person p){
    if(p==null){
        throw new NullPointerException("person");
    }
    return p.getName();
}

@Singular 默认值 暂时也没太大用处


@SneakyThrows


这个注解用在方法上,可以将方法中的代码用try-catch语句包裹起来,捕获异常并在catch中用Lombok.sneakyThrow(e)把异常抛出,可以使用@SneakyThrows(Exception.class)的形式指定抛出哪种异常


 @SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF-8");
    }


编译后:


@SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        try{
            return new String(bytes, "UTF-8");
        }catch(UnsupportedEncodingException uee){
            throw Lombok.sneakyThrow(uee);
        }
    }

这里有必要贴出来Lombok.sneakyThrow的代码:


 public static RuntimeException sneakyThrow(Throwable t) {
        if (t == null) {
            throw new NullPointerException("t");
        } else {
            return (RuntimeException)sneakyThrow0(t);
        }
    }
    private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
        throw t;
    }


其实就是转化为了RuntimeException,其实我想说,这个注解也没大用。毕竟我们碰到异常,是希望自己处理的


@Synchronized


这个注解用在类方法或者实例方法上,效果和synchronized关键字相同,区别在于锁对象不同,对于类方法和实例方法,synchronized关键字的锁对象分别是类的class对象和this对象,而@Synchronized得锁对象分别是私有静态final对象LOCK和私有final对象lock,当然,也可以自己指定锁对象


@Synchronized
    public static void hello() {
        System.out.println("world");
    }
    @Synchronized
    public int answerToLife() {
        return 42;
    }
    @Synchronized("readLock")
    public void foo() {
        System.out.println("bar");
    }


编译后:


public static void hello() {
        Object var0 = $LOCK;
        synchronized($LOCK) {
            System.out.println("world");
        }
    }
    public int answerToLife() {
        Object var1 = this.$lock;
        synchronized(this.$lock) {
            return 42;
        }
    }
    public void foo() {
        Object var1 = this.readLock;
        synchronized(this.readLock) {
            System.out.println("bar");
        }
    }


我只能说,这个注解也挺鸡肋的。

@Val 很强的类型推断 var注解,在Java10之后就不能使用了


class Parent {
    //private static final val set = new HashSet<String>(); //编译不通过
    public static void main(String[] args) {
        val set = new HashSet<String>();
        set.add("aa");
        System.out.println(set); //[aa]
    }
}

编译后:


class Parent {
    Parent() {
    }
    public static void main(String[] args) {
        HashSet<String> set = new HashSet();
        set.add("aa");
        System.out.println(set);
    }
}


这个和Java10里的Var很像,强大的类型推断。并且不能使用在全局变量上,只能使用在局部变量的定义中。


@Log、CommonsLog、Slf4j、XSlf4j、Log4j、Log4j2等日志注解


这个注解用在类上,可以省去从日志工厂生成日志对象这一步,直接进行日志记录,具体注解根据日志工具的不同而不同,同时,可以在注解中使用topic来指定生成log对象时的类名。不同的日志注解总结如下(上面是注解,下面是实际作用):


@CommonsLog
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@JBossLog
private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);


这个注解还是非常有用的,特别是Slf4j这个,在平时开发中挺有用的


@Slf4j
class Parent {
}


编译后:


class Parent {
    private static final Logger log = LoggerFactory.getLogger(Parent.class);
    Parent() {
    }
}


也可topic的名称:

@Slf4j
@CommonsLog(topic = "commonLog")
class Parent {
}


lombok中有experimental的包:

实验性因为:


1.我们可能想将这些特性和更完全的性质支持概念融为一体(普通话:这些性能还在研究)


2.新特性-需要社区反馈


@Accessors 一个为getter和setter设计的更流畅的注解


这个注解要搭配@Getter与@Setter使用,用来修改默认的setter与getter方法的形式。所以单独使用是没有意义的


@Accessors(fluent = true)
@Getter
@Setter
public class Demo extends Parent {
    private final int finalVal = 10;
    private String name;
    private int age;
}

编译后

public class Demo extends Parent {
    private final int finalVal = 10;
    private String name;
    private int age;
    public Demo() {
    }
    public int finalVal() {
        Objects.requireNonNull(this);
        return 10;
    }
    public String name() {
        return this.name;
    }
    public int age() {
        return this.age;
    }
    public Demo name(String name) {
        this.name = name;
        return this;
    }
    public Demo age(int age) {
        this.age = age;
        return this;
    }
}


它的三个参数解释:


1.chain 链式的形式 这个特别好用,方法连缀越来越方便了


2.fluent 流式的形式(若无显示指定chain的值,也会把chain设置为true)


3.prefix 生成指定前缀的属性的getter与setter方法,并且生成的getter与setter方法时会去除前缀


@Accessors(prefix = "xxx")
@Getter
@Setter
public class Demo extends Parent {
    private final int finalVal = 10;
    private String xxxName;
    private int age;
}


编译后:


public class Demo extends Parent {
    private final int finalVal = 10;
    private String xxxName;
    private int age;
    public Demo() {
    }
    public String getName() {
        return this.xxxName;
    }
    public void setName(String xxxName) {
        this.xxxName = xxxName;
    }
}


我们发现prefix可以在生成get/set的时候,去掉xxx等prefix前缀,达到很好的一致性。但是,但是需要注意,因为此处age没有匹配上xxx前缀,所有根本就不给生成,所以使用的时候一定要注意。


属性名没有一个以其中的一个前缀开头,则属性会被lombok完全忽略掉,并且会产生一个警告。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
9月前
|
XML Java 编译器
Java注解的底层源码剖析与技术认识
Java注解(Annotation)是Java 5引入的一种新特性,它提供了一种在代码中添加元数据(Metadata)的方式。注解本身并不是代码的一部分,它们不会直接影响代码的执行,但可以在编译、类加载和运行时被读取和处理。注解为开发者提供了一种以非侵入性的方式为代码提供额外信息的手段,这些信息可以用于生成文档、编译时检查、运行时处理等。
197 7
|
6月前
|
Java 编译器 开发者
注解的艺术:Java编程的高级定制
注解是Java编程中的高级特性,通过内置注解、自定义注解及注解处理器,可以实现代码的高度定制和扩展。通过理解和掌握注解的使用方法,开发者可以提高代码的可读性、可维护性和开发效率。在实际应用中,注解广泛用于框架开发、代码生成和配置管理等方面,展示了其强大的功能和灵活性。
146 25
|
11月前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
225 43
Java学习十六—掌握注解:让编程更简单
|
9月前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
338 5
|
10月前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
104 0
|
11月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
80 0
|
11月前
|
XML Java 数据格式
Java-spring注解的作用
Java-spring注解的作用
87 0
|
Java
4.15.1下面那一个属性与Java解释程序有关?
下面那一个属性与Java解释程序有关?
251 0
|
2月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
125 0