Lombok(三)

@SneakyThrows

让方法抛出指定的异常,该异常将会直接终止掉方法的运行,我们不能捕获,异常时直接结束,除非我们手动在方法上抛出异常。

Java代码(可以看到我们在main方法中调用print2的时候并没有提示我们捕获异常):

public class SneakyThrowsExample {

    @SneakyThrows({NullPointerException.class})
    public void print(Object s) throws Exception {
        System.out.println(s.toString());
    }

    @SneakyThrows({NullPointerException.class})
    public void print2(Object s) {
        System.out.println(s.toString());
    }

    public static void main(String[] args) {
        try {
            new SneakyThrowsExample().print(null);
        } catch (Exception e) {
            System.out.println("error");
            e.printStackTrace();
        }
        new SneakyThrowsExample().print2(null);
    }
}

编译后(方法体是全部被try/catch块包裹了,并且抛出了异常,但是我们并没有去捕获):

public class SneakyThrowsExample {
    public SneakyThrowsExample() {
    }

    public void print(Object s) throws Exception {
        try {
            System.out.println(s.toString());
        } catch (NullPointerException var3) {
            throw var3;
        }
    }

    public void print2(Object s) {
        try {
            System.out.println(s.toString());
        } catch (NullPointerException var3) {
            throw var3;
        }
    }

    public static void main(String[] args) {
        try {
            (new SneakyThrowsExample()).print((Object)null);
        } catch (Exception var2) {
            System.out.println("error");
            var2.printStackTrace();
        }

        (new SneakyThrowsExample()).print2((Object)null);
    }
}

@Synchronized

官方文档解释:

@synchronized是同步方法修改器的一个更安全的变体。与同步一样,注释只能在静态和实例方法上使用。它的操作类似于synchronized关键字,但是它锁定不同的对象。这个关键字锁定了this,但是注释锁定了一个名为$lock的字段,这个字段是私有的。

如果该字段不存在,它将为您创建。如果您注释一个静态方法,那么注释将锁定一个名为$LOCK的静态字段。

如果您愿意,您可以自己创建这些锁。$lock和$LOCK字段当然不会生成,如果您已经自己创建了它们。您还可以选择锁定另一个字段,将其指定为@synchronized注释的参数。在这个使用变体中,字段不会自动创建,您必须自己显式地创建它们,否则将会发出一个错误。

锁定this或您自己的类对象可能会有一些不幸的副作用,因为不在您的控制之下的其他代码也可以锁定这些对象,这可能导致竞争条件和其他讨厌的与线程相关的错误。

总结:

非静态方法,锁定字段$lock;

静态方法,锁定字段$LOCK;

自定义字段xxx时,需要显示申明xxx字段。

Java代码:

public class SynchronizedExample {
    private final Object readLock = new Object();

    @Synchronized
    public static void staticMethod() {
        System.out.println("world");
    }

    @Synchronized
    public int unStaticMethod() {
        return 42;
    }

    @Synchronized("readLock")
    public void customMethod() {
        System.out.println("bar");
    }
}

编译后:

public class SynchronizedExample {
    private static final Object $LOCK = new Object[0];
    private final Object $lock = new Object[0];
    private final Object readLock = new Object();

    public SynchronizedExample() {
    }

    public static void staticMethod() {
        Object var0 = $LOCK;
        synchronized($LOCK) {
            System.out.println("world");
        }
    }

    public int unStaticMethod() {
        Object var1 = this.$lock;
        synchronized(this.$lock) {
            return 42;
        }
    }

    public void customMethod() {
        Object var1 = this.readLock;
        synchronized(this.readLock) {
            System.out.println("bar");
        }
    }
}

配置文件:

lombok.synchronized.flagUsage = [warning | error] (default: not set)

官方文档解释:

如果$lock和/或$LOCK是自动生成的,那么字段将用一个空的Object[]初始化,而不仅仅是一个new Object(),因为大多数代码片段都显示了这个模式。Lombok是这样做的,因为一个新的对象不是可序列化的,但是空的数组是可以的。因此,使用@synchronized不会阻止您的对象被序列化。

在类中至少有一个@synchronized方法意味着将有一个锁字段,但是如果您稍后删除所有这些方法,那么将不再有一个锁字段。这意味着您需要预先确定serialVersionUID的变化。如果您打算通过java的序列化机制长期存储它们,我们建议您总是向您的类添加一个serialVersionUID。如果您这样做,从您的方法中删除所有的@synchronized注释将不会破坏串行化。

如果您想知道为什么当您为锁对象选择自己定义的名字时,一个字段不会自动生成:因为如果这样做,在字段名中输入错误将导致很难找到bug!

@Getter(lazy=true)

官方文档解释:

您可以让lombok生成一个getter,它将在第一次调用这个getter的时候计算一个值一次,然后从那时开始缓存它。如果计算值需要大量CPU,或者值占用大量内存,那么这一点很有用。要使用这个特性,可以创建一个私有的final变量,用要运行的表达式来初始化它,并使用@getter(惰性=true)对您的字段进行注释。该字段将隐藏在您的代码的其余部分,当getter被首次调用时,表达式将会被调用不超过一次。没有任何神奇的标记值(例如,即使您的昂贵计算的结果是null,结果也会被缓存),并且您的昂贵计算不必是线程安全的,因为lombok会处理锁定。

解释:在调用该缓存起来的方法时,该方法只会被调用一次(可以看编译后的代码,会执行判断,如果缓存不为null就会直接返回)。

Java代码(由于集合使用Iterator遍历的时候不能对集合进行修改,所以expensive方法中没有使用foreach循环,使用foreach循环在编译后的代码就是用的Iterator进行遍历的):

public class GetterLazyExample {

    @Getter(lazy = true)
    private final double cached = expensive();
    @Setter
    @Getter
    private List<Double> cacheValue;

    private double expensive() {
        double result = 0;
        for (int i = 0; i < cacheValue.size(); i++) {
            result += cacheValue.get(i);
        }
        return result;
    }

    public static void main(String[] args) {
        GetterLazyExample example = new GetterLazyExample();
        List<Double> ds = new ArrayList<>();
        ds.add(1d);
        ds.add(2d);
        ds.add(3d);
        example.setCacheValue(ds);
        System.out.println(example.getCached());
        example.getCacheValue().add(4d);
        System.out.println(example.getCached());
    }
}

编译后的代码(可以看到类在实例化之后,第一次调用getCatched方法的时候执行了一次计算,此后cached的值不为null之后,就不会在执行计算代码了,即官方文档解释的计算只会执行不超过一次):

public class GetterLazyExample {
    private final AtomicReference<Object> cached = new AtomicReference();
    private List<Double> cacheValue;

    public GetterLazyExample() {
    }

    private double expensive() {
        double result = 0.0D;

        for(int i = 0; i < this.cacheValue.size(); ++i) {
            result += (Double)this.cacheValue.get(i);
        }
        return result;
    }

    public static void main(String[] args) {
        GetterLazyExample example = new GetterLazyExample();
        List<Double> ds = new ArrayList();
        ds.add(1.0D);
        ds.add(2.0D);
        ds.add(3.0D);
        example.setCacheValue(ds);
        System.out.println(example.getCached());
        example.getCacheValue().add(4.0D);
        example.setCacheValue(ds);
        System.out.println(example.getCached());
        System.out.println(example.getCacheValue().get(3));
    }

    public double getCached() {
        Object value = this.cached.get();
        if (value == null) {
            AtomicReference var2 = this.cached;
            synchronized(this.cached) {
                value = this.cached.get();
                if (value == null) {
                    double actualValue = this.expensive();
                    value = actualValue;
                    this.cached.set(value);
                }
            }
        }

        return (Double)value;
    }

    public void setCacheValue(List<Double> cacheValue) {
        this.cacheValue = cacheValue;
    }

    public List<Double> getCacheValue() {
        return this.cacheValue;
    }
}

@Log (and friends)

使用该注解,会在类中生成名称为log的final的引用,相当于我们自己定义了一个引用。

使用的时候必须要用相应的jar包。

官方文档解释:

您可以让lombok生成一个getter,它将在第一次调用这个getter的时候计算一个值一次,然后从那时开始缓存它。如果计算值需要大量CPU,或者值占用大量内存,那么这一点很有用。要使用这个特性,可以创建一个私有的final变量,用要运行的表达式来初始化它,并使用@getter(惰性=true)对您的字段进行注释。该字段将隐藏在您的代码的其余部分,当getter被首次调用时,表达式将会被调用不超过一次。没有任何神奇的标记值(例如,即使您的昂贵计算的结果是null,结果也会被缓存),并且您的昂贵计算不必是线程安全的,因为lombok会处理锁定。

您将@Log的变体放在您的类上(任何一个应用于您所使用的日志系统);然后,您有一个静态的final log字段,初始化到您的类名,然后您可以使用它来编写日志语句。

有几种选择:(看字很不清楚,下面有截图)

@CommonsLog

Creates private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@JBossLog

Creates private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);

@Log

Creates private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j

Creates private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2

Creates private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j

Creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

@XSlf4j

Creates private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

在默认情况下,日志记录器的topic将是带有@log注释的类的类名。这可以通过指定主题参数来定制。例如:@XSlf4j(topic=“customLog”)。

165722_KGj8_3298044.png

Java代码:

@Log
public class LogExample {

    public static void main(String... args) {
        log.info("Something's wrong here");
    }
}

@Slf4j
class LogExampleOther {

    public static void main(String... args) {
        log.error("Something else is wrong here");
    }
}

@CommonsLog(topic = "CounterLog")
class LogExampleCategory {

    public static void main(String... args) {
        log.error("Calling the 'CounterLog' with a message");
    }
}

编译后:

public class LogExample {
    private static final Logger log = Logger.getLogger(LogExample.class.getName());

    public LogExample() {
    }

    public static void main(String... args) {
        log.info("Something's wrong here");
    }
}

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

    LogExampleOther() {
    }

    public static void main(String... args) {
        log.error("Something else is wrong here");
    }
}

class LogExampleCategory {
    private static final Log log = LogFactory.getLog("CounterLog");

    LogExampleCategory() {
    }

    public static void main(String... args) {
        log.error("Calling the 'CounterLog' with a message");
    }
}

配置文件:

lombok.log.fieldName = an identifier (default: log)

配置生成的日志记录器引用的名称。

lombok.log.fieldIsStatic = [true | false] (default: true)

日志应用是否是静态的。

lombok.log.flagUsage = [warning | error] (default: not set)

lombok.log.apacheCommons.flagUsage = [warning | error] (default: not set)

lombok.log.javaUtilLogging.flagUsage = [warning | error] (default: not set)

lombok.log.jbosslog.flagUsage = [warning | error] (default: not set)

lombok.log.log4j.flagUsage = [warning | error] (default: not set)

lombok.log.log4j2.flagUsage = [warning | error] (default: not set)

lombok.log.slf4j.flagUsage = [warning | error] (default: not set)

lombok.log.xslf4j.flagUsage = [warning | error] (default: not set)

官方文档解释:

如果一个名为log的字段已经存在,就会发出一个警告,并且不会生成任何代码。

lombok不同的日志注释的未来特性是找到对logger字段的调用,如果所选的日志框架支持它,并且日志级别可以通过日志调用来确定,那么可以使用if语句来保护它。这样,如果日志语句最终被忽略,那么就完全避免了对日志字符串的潜在开销。这就意味着你不应该添加任何副作用的代码在你日志记录中。

Experimental(实验性功能)

官方文档解释:

可以使用Lombok javadoc,但是我们建议这些特性。

在您的正常的lombok安装中可以使用实验特性,但是不像lombok的核心特性那样健壮。特别是,实验特点:

不像核心特性那样测试。

不要像核心功能一样快速地修复bug。

如果我们找到一种不同的、更好的方法来解决同样的问题,可能会有一些api会发生变化。

如果这个特性太难支持或者没有足够的样板文件,可能会完全消失。

那些接收到积极的社区反馈的特性,以及看起来能够产生干净、灵活的代码的特性最终将被作为核心特性接受,并从实验包中移出。

这部分中很多注解在之前就已经用过了,暂不写笔记了,有空再写吧~~

(三)over~~

 

 

转载于:https://my.oschina.net/wtkid/blog/1611925

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值