当前位置: 首页 > 编程日记 > 正文

40.lombok在IntelliJ IDEA下的使用

转自:https://www.cnblogs.com/yjmyzz/p/lombok-with-intellij-idea.html

lombok是一款可以精减java代码、提升开发人员生产效率的辅助工具,利用注解在编译期自动生成setter/getter/toString()/constructor之类的代码。代码越少,意味着出bug的可能性越低。

官网地址:https://projectlombok.org/ 首页有一段几分钟的演示视频,看完就明白是怎么回事了。

先来二段对比代码:

这是用lombok后的java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import lombok.*;
import lombok.extern.slf4j.Slf4j;
import java.io.ByteArrayInputStream;
import java.io.*;
import java.util.ArrayList;
@Data
@Slf4j
@AllArgsConstructor
public class Something {
    private String name;
    private final String country;
    private final Object lockObj = new Object();
    public void sayHello(@NonNull String target) {
        String content = String.format("hello,%s", target);
        System.out.println(content);
        log.info(content);
    }
    public void addBalabala() {
        val list = new ArrayList<String>();
        list.add("haha");
        System.out.println(list.size());
    }
    @SneakyThrows(IOException.class)
    public void closeBalabala() {
        @Cleanup InputStream is = new ByteArrayInputStream("hello world".getBytes());
        System.out.println(is.available());
    }
    @Synchronized("lockObj")
    public void lockMethod() {
        System.out.println("test lock method");
    }
}

等效于下面这段java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import java.beans.ConstructorProperties;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import lombok.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Something {
    private static final Logger log = LoggerFactory.getLogger(Something.class);
    private String name;
    private final String country;
    private final Object lockObj = new Object();
    public void sayHello(@NonNull String target) {
        if(target == null) {
            throw new NullPointerException("target");
        else {
            String content = String.format("hello,%s"new Object[]{target});
            System.out.println(content);
            log.info(content);
        }
    }
    public void addBalabala() {
        ArrayList list = new ArrayList();
        list.add("haha");
        System.out.println(list.size());
    }
    public void closeBalabala() {
        try {
            ByteArrayInputStream $ex = new ByteArrayInputStream("hello world".getBytes());
            try {
                System.out.println($ex.available());
            finally {
                if(Collections.singletonList($ex).get(0) != null) {
                    $ex.close();
                }
            }
        catch (IOException var6) {
            throw var6;
        }
    }
    public void lockMethod() {
        Object var1 = this.lockObj;
        synchronized(this.lockObj) {
            System.out.println("test lock method");
        }
    }
    public String getName() {
        return this.name;
    }
    public String getCountry() {
        return this.country;
    }
    public Object getLockObj() {
        return this.lockObj;
    }
    public void setName(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        if(o == this) {
            return true;
        else if(!(o instanceof Something)) {
            return false;
        else {
            Something other = (Something)o;
            if(!other.canEqual(this)) {
                return false;
            else {
                label47: {
                    String this$name = this.getName();
                    String other$name = other.getName();
                    if(this$name == null) {
                        if(other$name == null) {
                            break label47;
                        }
                    else if(this$name.equals(other$name)) {
                        break label47;
                    }
                    return false;
                }
                String this$country = this.getCountry();
                String other$country = other.getCountry();
                if(this$country == null) {
                    if(other$country != null) {
                        return false;
                    }
                else if(!this$country.equals(other$country)) {
                    return false;
                }
                Object this$lockObj = this.getLockObj();
                Object other$lockObj = other.getLockObj();
                if(this$lockObj == null) {
                    if(other$lockObj != null) {
                        return false;
                    }
                else if(!this$lockObj.equals(other$lockObj)) {
                    return false;
                }
                return true;
            }
        }
    }
    protected boolean canEqual(Object other) {
        return other instanceof Something;
    }
    public int hashCode() {
        boolean PRIME = true;
        byte result = 1;
        String $name = this.getName();
        int result1 = result * 59 + ($name == null?0:$name.hashCode());
        String $country = this.getCountry();
        result1 = result1 * 59 + ($country == null?0:$country.hashCode());
        Object $lockObj = this.getLockObj();
        result1 = result1 * 59 + ($lockObj == null?0:$lockObj.hashCode());
        return result1;
    }
    public String toString() {
        return "Something(name=" this.getName() + ", country=" this.getCountry() + ", lockObj=" this.getLockObj() + ")";
    }
    @ConstructorProperties({"name""country"})
    public Something(String name, String country) {
        this.name = name;
        this.country = country;
    }
}

大概减少了2/3的代码,各种注解的详细用法,请参考:https://projectlombok.org/features/index.html



IDEA下使用时,可以通过插件的形式安装,插件下载地址:https://github.com/mplushnikov/lombok-intellij-plugin/releases

然后

Plugins -> Install plugin from disk... 选择下载的zip包安装,重启idea即可。

另外,还有一个关键设置:

为了让设置生效,建议再重启一次idea,然后就可以开心的编码了,可以ide里可以直接看到生成的方法:(下图中打红圈的都是自动生成的)

http://www.cnblogs.com/yjmyzz/p/lombok-with-intellij-idea.html

Contents

  • Introduction
  • Installation
  • Lombok Annotations
    • @Getter and @Setter
    • @NonNull
    • @ToString
    • @EqualsAndHashCode
    • @Data
    • @Cleanup
    • @Synchronized
    • @SneakyThrows
  • Costs and Benefits
    • What are we missing?
    • Limitations
    • Controversy
  • Summary
  • References

Introduction

"Boilerplate" is a term used to describe code that is repeated in many parts of an application with little alteration. One of the most frequently voiced criticisms of the Java language is the volume of this type of code that is found in most projects. This problem is frequently a result of design decisions in various libraries, but is exacerbated by limitations in the language itself. Project Lombok aims to reduce the prevalence of some of the worst offenders by replacing them with a simple set of annotations.

While it is not uncommon for annotations to be used to indicate usage, to implement bindings or even to generate code used by frameworks, they are generally not used for the generation of code that is directly utilized by the application. This is partly because doing so would require that the annotations be eagerly processed at development time. Project Lombok does just that. By integrating into the IDE, Project Lombok is able to inject code that is immediately available to the developer. For example, simply adding the @Data annotation to a data class, as below, results in a number of new methods in the IDE:

Image illustrating the availability of new methods on a data class in Eclipse.

Installation

Project Lombok is available as a single jar file on the project site. It includes the APIs for development as an installer for IDE integration. On most systems, simply double-clicking the jar file will launch the installer. If the system is not configured to correctly launch jar files, it can also be run from the command line as follows:

java -jar lombok.jar

The installer will attempt to detect the location of a supported IDE. If it cannot correctly determine where the IDE is installed, the location can be specified manually. Simply click "Install/Update" and IDE integration is complete. At the time of this article's writing, only Eclipse and NetBeans are supported. However, the release of the IntelliJ IDEA source code has placed IDEA support as a possibility for future releases, and limited success has already been reported with JDeveloper.

Screenshot of the Lombok Installer

The jar file will still need to be included in the classpath of any projects that will use Project Lombok annotations. Maven users can include Lombok as a dependency by adding this to the project pom.xml file:

<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>0.9.2</version></dependency>
</dependencies>
<repositories><repository><id>projectlombok.org</id><url>http://projectlombok.org/mavenrepo</url></repository>
</repositories>

Lombok Annotations

It is not uncommon for a typical Java project to devote hundreds of lines of code to the boilerplate required for defining simple data classes. These classes generally contain a number of fields, getters and setters for those fields, as well as equals and hashCode implementations. In the simplest scenarios, Project Lombok can reduce these classes to the required fields and a single @Data annotation.

Of course, the simplest scenarios are not necessarily the ones that developers face on a day-to-day basis. For that reason, there are a number of annotations in Project Lombok to allow for more fine grained control over the structure and behavior of a class.

@Getter and @Setter

The @Getter and @Setter annotations generate a getter and setter for a field, respectively. The getters generated correctly follow convention for boolean properties, resulting in an isFoo getter method name instead of getFoofor any boolean field foo. It should be noted that if the class to which the annotated field belongs contains a method of the same name as the getter or setter to be generated, regardless of parameter or return types, no corresponding method will be generated.

Both the @Getter and @Setter annotations take an optional parameter to specify the access level for the generated method.

Lombok annotated code:

@Getter @Setter private boolean employed = true;
@Setter(AccessLevel.PROTECTED) private String name;

Equivalent Java source code:

private boolean employed = true;
private String name;public boolean isEmployed() {return employed;
}public void setEmployed(final boolean employed) {this.employed = employed;
}protected void setName(final String name) {this.name = name;
}

@NonNull

The @NonNull annotation is used to indicate the need for a fast-fail null check on the corresponding member. When placed on a field for which Lombok is generating a setter method, a null check will be generated that will result in a NullPointerException should a null value be provided. Additionally, if Lombok is generating a constructor for the owning class then the field will be added to the constructor signature and the null check will be included in the generated constructor code.

This annotation mirrors @NotNull and @NonNull annotations found in IntelliJ IDEA and FindBugs, among others. Lombok is annotation agnostic with regards to these variations on the theme. If Lombok comes across any member annotated with any annotation of the name @NotNull or @NonNull, it will honor it by generating the appropriate corresponding code. The authors of Project Lombok further comment that, in the event that annotation of this type is added to Java, then the Lombok version will be subject to removal.

Lombok annotated code from the class Family:

@Getter @Setter @NonNull
private List<Person> members;

Equivalent Java source code:

@NonNull
private List<Person> members;public Family(@NonNull final List<Person> members) {if (members == null) throw new java.lang.NullPointerException("members");this.members = members;
}@NonNull
public List<Person> getMembers() {return members;
}public void setMembers(@NonNull final List<Person> members) {if (members == null) throw new java.lang.NullPointerException("members");this.members = members;
}

@ToString

This annotation generates an implementation of the toString method. By default, any non-static fields will be included in the output of the method in name-value pairs. If desired, the inclusion of the property names in the output can be suppressed by setting the annotation parameter includeFieldNames to false.

Specific fields can be excluded from the output of the generated method by including their field names in the exclude parameter. Alternatively, the of parameter can be used to list only those fields which are desired in the output. The output of the toString method of a superclass can also be included by setting the callSuper parameter to true.

Lombok annotated code:

@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {private boolean someBoolean = true;private String someStringField;private float someExcludedField;
}

Equivalent Java source code:

public class Foo extends Bar {private boolean someBoolean = true;private String someStringField;private float someExcludedField;@java.lang.Overridepublic java.lang.String toString() {return "Foo(super=" + super.toString() +", someBoolean=" + someBoolean +", someStringField=" + someStringField + ")";}
}

@EqualsAndHashCode

This class level annotation will cause Lombok to generate both equals and hashCode methods, as the two are tied together intrinsically by the hashCode contract. By default, any field in the class that is not static or transient will be considered by both methods. Much like @ToString, the exclude parameter is provided to prevent field from being included in the generated logic. One can also use the of parameter to list only those fields should be considered.

Also like @ToString, there is a callSuper parameter for this annotation. Setting it to true will cause equals to verify equality by calling the equals from the superclass before considering fields in the current class. For thehashCode method, it results in the incorporation of the results of the superclass's hashCode in the calculation of the hash. When setting callSuper to true, be careful to make sure that the equals method in the parent class properly handles instance type checking. If the parent class checks that the class is of a specific type and not merely that the classes of the two objects are the same, this can result in undesired results. If the superclass is using a Lombok generated equals method, this is not an issue. However, other implementations may not handle this situation correctly. Also note that setting callSuper to true cannot be done when the class only extends Object, as it would result in an instance equality check that short-circuits the comparison of fields. This is due to the generated method calling the equals implementation on Object, which returns false if the two instances being compared are not the same instance. As a result, Lombok will generate a compile time error in this situation.

Lombok annotated code:

@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
public class Person extends SentientBeing {enum Gender { Male, Female }@NonNull private String name;@NonNull private Gender gender;private String ssn;private String address;private String city;private String state;private String zip;
}

Equivalent Java source code:

public class Person extends SentientBeing {enum Gender {/*public static final*/ Male /* = new Gender() */,/*public static final*/ Female /* = new Gender() */;}@NonNullprivate String name;@NonNullprivate Gender gender;private String ssn;private String address;private String city;private String state;private String zip;@java.lang.Overridepublic boolean equals(final java.lang.Object o) {if (o == this) return true;if (o == null) return false;if (o.getClass() != this.getClass()) return false;if (!super.equals(o)) return false;final Person other = (Person)o;if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;return true;}@java.lang.Overridepublic int hashCode() {final int PRIME = 31;int result = 1;result = result * PRIME + super.hashCode();result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());return result;}
}

@Data

The @Data annotation is likely the most frequently used annotation in the Project Lombok toolset. It combines the functionality of @ToString@EqualsAndHashCode@Getter and @Setter. Essentially, using @Data on a class is the same as annotating the class with a default @ToString and @EqualsAndHashCode as well as annotating each field with both @Getter and @Setter. Annotation a class with @Data also triggers Lombok's constructor generation. This adds a public constructor that takes any @NonNull or final fields as parameters. This provides everything needed for a Plain Old Java Object (POJO).

While @Data is extremely useful, it does not provide the same granularity of control as the other Lombok annotations. In order to override the default method generation behaviors, annotate the class, field or method with one of the other Lombok annotations and specify the necessary parameter values to achieve the desired effect.

@Data does provide a single parameter option that can be used to generate a static factory method. Setting the value of the staticConstructor parameter to the desired method name will cause Lombok to make the generated constructor private and expose a a static factory method of the given name.

Lombok annotated code:

@Data(staticConstructor="of")
public class Company {private final Person founder;private String name;private List<Person> employees;
}

Equivalent Java source code:

public class Company {private final Person founder;private String name;private List<Person> employees;private Company(final Person founder) {this.founder = founder;}public static Company of(final Person founder) {return new Company(founder);}public Person getFounder() {return founder;}public String getName() {return name;}public void setName(final String name) {this.name = name;}public List<Person> getEmployees() {return employees;}public void setEmployees(final List<Person> employees) {this.employees = employees;}@java.lang.Overridepublic boolean equals(final java.lang.Object o) {if (o == this) return true;if (o == null) return false;if (o.getClass() != this.getClass()) return false;final Company other = (Company)o;if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;return true;}@java.lang.Overridepublic int hashCode() {final int PRIME = 31;int result = 1;result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());return result;}@java.lang.Overridepublic java.lang.String toString() {return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";}
}

@Cleanup

The @Cleanup annotation can be used to ensure that allocated resources are released. When a local variable is annotated with @Cleanup, any subsequent code is wrapped in a try/finally block that guarantees that the cleanup method is called at the end of the current scope. By default @Cleanup assumes that the cleanup method is named "close", as with input and output streams. However, a different method name can be provided to the annotation'svalue parameter. Only cleanup methods which take no parameters are able to be used with this annotation.

There is also a caveat to consider when using the @Cleanup annotation. In the event that an exception is thrown by the cleanup method, it will preempt any exception that was thrown in the method body. This can result in the actual cause of an issue being buried and should be considered when choosing to use Project Lombok's resource management. Furthermore, with automatic resource management on the horizon in Java 7, this particular annotation is likely to be relatively short-lived.

Lombok annotated code:

public void testCleanUp() {try {@Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();baos.write(new byte[] {'Y','e','s'});System.out.println(baos.toString());} catch (IOException e) {e.printStackTrace();}
}

Equivalent Java source code:

public void testCleanUp() {try {ByteArrayOutputStream baos = new ByteArrayOutputStream();try {baos.write(new byte[]{'Y', 'e', 's'});System.out.println(baos.toString());} finally {baos.close();}} catch (IOException e) {e.printStackTrace();}
}

@Synchronized

Using the synchronized keyword on a method can result in unfortunate effects, as any developer who has worked on multi-threaded software can attest. The synchronized keyword will lock on the current object (this) in the case of an instance method or on the class object for a static method. This means that there is the potential for code outside of the control of the developer to lock on the same object, resulting in a deadlock. It is generally advisable to instead lock explicitly on a separate object that is dedicated solely to that purpose and not exposed in such a way as to allow unsolicited locking. Project Lombok provides the @Synchronized annotation for that very purpose.

Annotating an instance method with @Synchronized will prompt Lombok to generate a private locking field named $lock on which the method will lock prior to executing. Similarly, annotating a static method in the same way will generate a private static object named $LOCK for the static method to use in an identical fashion. A different locking object can be specified by providing a field name to the annotation's value parameter. When a field name is provided, the developer must define the property as Lombok will not generate it.

Lombok annotated code:

private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");@Synchronized
public String synchronizedFormat(Date date) {return format.format(date);
}

Equivalent Java source code:

private final java.lang.Object $lock = new java.lang.Object[0];
private DateFormat format = new SimpleDateFormat("MM-dd-YYYY");public String synchronizedFormat(Date date) {synchronized ($lock) {return format.format(date);}
}

@SneakyThrows

@SneakyThrows is probably the Project Lombok annotation with the most detractors, since it is a direct assault on checked exceptions. There is a lot of disagreement with regards to the use of checked exceptions, with a large number of developers holding that they are a failed experiment. These developers will love @SneakyThrows. Those developers on the other side of the checked/unchecked exception fence will most likely view this as hiding potential problems.

Throwing IllegalAccessException would normally generate an "Unhandled exception" error if IllegalAccessException, or some parent class, is not listed in a throws clause:

Screenshot of Eclipse generating an error message regarding unhandled exceptions.

When annotated with @SneakyThrows, the error goes away.

Screenshot of a method annotated with @SneakyThrows and generating no error in Eclipse.

By default, @SneakyThrows will allow any checked exception to be thrown without declaring in the throws clause. This can be limited to a particular set of exceptions by providing an array of throwable classes ( Class<? extends Throwable>) to the value parameter of the annotation.

Lombok annotated code:

@SneakyThrows
public void testSneakyThrows() {throw new IllegalAccessException();
}

Equivalent Java source code:

public void testSneakyThrows() {try {throw new IllegalAccessException();} catch (java.lang.Throwable $ex) {throw lombok.Lombok.sneakyThrow($ex);}
}

A look at the above code and the signature of Lombok.sneakyThrow(Throwable) would lead most to believe that the exception is being wrapped in a RuntimeException and re-thrown, however this is not the case. ThesneakyThrow method will never return normally and will instead throw the provided throwable completely unaltered.

Costs and Benefits

As with any technology choice, there are both positive and negative effects of using Project Lombok. Incorporating Lombok's annotations in a project can greatly reduce the number of lines of boilerplate code that are either generated in the IDE or written by hand. This results in reduced maintenance overhead, fewer bugs and more readable classes.

That is not to say that there are not downsides to using Project Lombok annotations in your project. Project Lombok is largely aimed at filling gaps in the Java language. As such, there is the possibility that changes to the language will take place that preclude the use of Lombok's annotations, such as the addition of first class property support. Additionally, when used in combination with annotation-based object-relational mapping (ORM) frameworks, the number of annotations on data classes can begin to get unwieldy. This is largely offset by the amount of code that is superseded by the Lombok annotations. However, those who shun the frequent use of annotations may choose to look the other way.

What is missing?

Project Lombok provides the delombok utility for replacing the Lombok annotations with equivalent source code. This can be done for an entire source directory via the command line.

java -jar lombok.jar delombok src -d src-delomboked

Alternatively, an Ant task is provided for incorporation into a build process.

<target name="delombok"><taskdef classname="lombok.delombok.ant.DelombokTask"classpath="WebRoot/WEB-INF/lib/lombok.jar" name="delombok" /><mkdir dir="src-delomboked" /><delombok verbose="true" encoding="UTF-8" to="src-delomboked"from="src" />
</target>

Both delombok and the corresponding Ant task come packaged in the core lombok.jar download. Along with allowing Lombok annotations to be useful in applications built using Google Web Toolkit (GWT) or other incompatible frameworks, running delombok on the Person class makes it easy to contrast the class as written using the Lombok annotations against code that includes the equivalent boilerplate inline.

package com.ociweb.jnb.lombok;import java.util.Date;import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;@Data
@EqualsAndHashCode(exclude={"address","city","state","zip"})
public class Person {enum Gender { Male, Female }@NonNull private String firstName;@NonNull private String lastName;@NonNull private final Gender gender;@NonNull private final Date dateOfBirth;private String ssn;private String address;private String city;private String state;private String zip;
}

The code utilizing the Project Lombok annotations is significantly more concise than the equivalent class with the boilerplate included.

package com.ociweb.jnb.lombok;import java.util.Date;
import lombok.NonNull;public class Person {enum Gender {/*public static final*/ Male /* = new Gender() */,/*public static final*/ Female /* = new Gender() */;}@NonNullprivate String firstName;@NonNullprivate String lastName;@NonNullprivate final Gender gender;@NonNullprivate final Date dateOfBirth;private String ssn;private String address;private String city;private String state;private String zip;public Person(@NonNull final String firstName, @NonNull final String lastName,@NonNull final Gender gender, @NonNull final Date dateOfBirth) {if (firstName == null)throw new java.lang.NullPointerException("firstName");if (lastName == null)throw new java.lang.NullPointerException("lastName");if (gender == null)throw new java.lang.NullPointerException("gender");if (dateOfBirth == null)throw new java.lang.NullPointerException("dateOfBirth");this.firstName = firstName;this.lastName = lastName;this.gender = gender;this.dateOfBirth = dateOfBirth;}@NonNullpublic String getFirstName() {return firstName;}public void setFirstName(@NonNull final String firstName) {if (firstName == null)throw new java.lang.NullPointerException("firstName");this.firstName = firstName;}@NonNullpublic String getLastName() {return lastName;}public void setLastName(@NonNull final String lastName) {if (lastName == null)throw new java.lang.NullPointerException("lastName");this.lastName = lastName;}@NonNullpublic Gender getGender() {return gender;}@NonNullpublic Date getDateOfBirth() {return dateOfBirth;}public String getSsn() {return ssn;}public void setSsn(final String ssn) {this.ssn = ssn;}public String getAddress() {return address;}public void setAddress(final String address) {this.address = address;}public String getCity() {return city;}public void setCity(final String city) {this.city = city;}public String getState() {return state;}public void setState(final String state) {this.state = state;}public String getZip() {return zip;}public void setZip(final String zip) {this.zip = zip;}@java.lang.Overridepublic java.lang.String toString() {return "Person(firstName=" + firstName + ", lastName=" + lastName + ", gender=" + gender + ", dateOfBirth=" + dateOfBirth +", ssn=" + ssn + ", address=" + address + ", city=" + city +", state=" + state + ", zip=" + zip + ")";}@java.lang.Overridepublic boolean equals(final java.lang.Object o) {if (o == this) return true;if (o == null) return false;if (o.getClass() != this.getClass()) return false;final Person other = (Person)o;if (this.firstName == null? other.firstName != null: !this.firstName.equals(other.firstName))return false;if (this.lastName == null? other.lastName != null: !this.lastName.equals(other.lastName))return false;if (this.gender == null? other.gender != null: !this.gender.equals(other.gender))return false;if (this.dateOfBirth == null? other.dateOfBirth != null: !this.dateOfBirth.equals(other.dateOfBirth))return false;if (this.ssn == null? other.ssn != null: !this.ssn.equals(other.ssn))return false;return true;}@java.lang.Overridepublic int hashCode() {final int PRIME = 31;int result = 1;result = result * PRIME +(this.firstName == null ? 0 : this.firstName.hashCode());result = result * PRIME +(this.lastName == null ? 0 : this.lastName.hashCode());result = result * PRIME +(this.gender == null ? 0 : this.gender.hashCode());result = result * PRIME +(this.dateOfBirth == null ? 0 : this.dateOfBirth.hashCode());result = result * PRIME +(this.ssn == null ? 0 : this.ssn.hashCode());return result;}
}

Keep in mind that this is not just code that normally has to be written, but must also be read by maintaining developers. This means that, when using the annotations provided by Project Lombok, developers do not have to wade through countless lines of code in order to determine if the class in question is a simple data class or something more sinister.

Limitations

While Project Lombok does some dramatic things to make a developer's life easier, it has its limitations. Browsing the issues list will quickly illuminate some of the current shortcomings, most of which are minor. One important problem is the inability to detect the constructors of a superclass. This means that if a superclass has no default constructor any subclasses cannot use the @Data annotation without explicitly writing a constructor to make use of the available superclass constructor. Since Project Lombok respects any methods that match the name of a method to be generated, the majority of its feature shortcomings can be overcome using this approach.

Controversy

A number of issues have been raised against the use of Project Lombok. The most common argument holds that annotations were intended for "meta" information and are not to be used in such a way that would leave the codebase unable to be compiled were they removed. This is certainly the situation with Lombok annotations. New methods result from these annotations that are intended to be used not only by a framework, but by other parts of the application. Project Lombok's development-time support is its bread and butter, but this does have consequences, not the least of which is limited IDE support.

As previously stated, @SneakyThrows is bound to stir up the age-old argument over checked and unchecked exceptions. Opinions on this debate are often almost religious in their ferocity. As such, the arguments against the use of @SneakyThrows are also sure to excite fervor among the passionate.

Another point of contention is the implementation of both the code supporting IDE integration as well as the javac annotation processor. Both of these pieces of Project Lombok make use of non-public APIs to accomplish their sorcery. This means that there is a risk that Project Lombok will be broken with subsequent IDE or JDK releases. Here is how one of the project founders, Reinier Zwitserloot described the situation:

It's a total hack. Using non-public API. Presumptuous casting (knowing that an
annotation processor running in javac will get an instance of JavacAnnotationProcessor,
which is the internal implementation of AnnotationProcessor (an interface), which
so happens to have a couple of extra methods that are used to get at the live AST).On eclipse, it's arguably worse (and yet more robust) - a java agent is used to inject
code into the eclipse grammar and parser class, which is of course entirely non-public
API and totally off limits.If you could do what lombok does with standard API, I would have done it that way, but
you can't. Still, for what its worth, I developed the eclipse plugin for eclipse v3.5
running on java 1.6, and without making any changes it worked on eclipse v3.4 running
on java 1.5 as well, so it's not completely fragile.

Summary

Project Lombok is a powerful tool for the pragmatic developer. It provides a set of useful annotations for eliminating a tremendous amount of boilerplate code from your Java classes. In the best cases, a mere five characters can replace hundreds of lines of code. The result is Java classes that are clean, concise and easy to maintain. These benefits do come with a cost however. Using Project Lombok in an IntelliJ IDEA shop is simply not yet a viable option. There is a risk of breakage with IDE and JDK upgrades as well as controversy surrounding the goals and implementation of the project. What all this translates to is no different than what must be considered for any technology choice. There are always gains to be made and losses to be had. The question is simply whether or not Project Lombok can provide more value than cost for the project at hand. If nothing else, Project Lombok is sure to inject some new life into the discussion of language features that have withered on the vine thus far and that is a win from any perspective.

References

  • Project Lombok -
    http://projectlombok.org
  • Lombok API Documentation -
    http://projectlombok.org/api/index.html
  • Project Lombok Issues List -
    http://code.google.com/p/projectlombok/issues/list
  • Use Lombok via Maven -
    http://projectlombok.org/mavenrepo/index.html
  • Project Lombok Google Group -
    http://groups.google.com/group/project-lombok
  • Reviewing Project Lombok or the Right Way to Write a Library -
    http://www.cforcoding.com/2009/11/reviewing-project-lombok-or-right-way.html
  • Morbok: Extensions for Lombok -
    http://code.google.com/p/morbok
  • Using Project Lombok with JDeveloper -
    http://kingsfleet.blogspot.com/2009/09/project-lombok-interesting-bean.html
  • Example Code -
    LombokExample.zip

Thanks to Mark Volkmann, Eric Burke, Mario Aquino and Lance Finney for reviewing and providing suggestions for this article, and a special thanks to Mark Volkmann for introducing me to Project Lombok.

http://jnb.ociweb.com/jnb/jnbJan2010.html

转载于:https://www.cnblogs.com/sharpest/p/7890698.html

相关文章:

C++之Boost使用

1. Get & Build & Install Boost download boost from http://www.boost.org/ 进入boost目录&#xff0c;使用命令&#xff1a; ./bootstrap.sh --prefixpath/to/installation ./b2 install 如此之后&#xff1a; leave Boost binaries in the lib/ subdirectory…

这就是芬兰:先让全国1%的人学起AI!

译者 | 大鱼责编 | 琥珀出品 | AI科技大本营【AI科技大本营导语】全球最大的手机制造商诺基亚、著名游戏《愤怒的小鸟》的开发商 Rovio&#xff0c;这两大曾名噪一时的科技公司都来自同一个国家——芬兰。很多人会问&#xff1a;在如此激烈的竞争环境下&#xff0c;为什么如此小…

Linux 裸设备基础知识(转)

1、裸设备定义&#xff1a;一块没有分区的硬盘&#xff0c;称为原始设备(RAW DEVICE)或者是一个分区&#xff0c;但是没有用EXT3,OCFS等文件系统格式化,称为原始分区(RAW PARTITION)以上两者都是裸设备 2、裸设备的绑定有文件系统的分区是采用mount的方式挂载到某一个挂载点的…

吴恩达与LG握手合作!

图片来自LG官网作者 | 琥珀出品 | AI科技大本营在近日举办的 CES 大会上&#xff0c;人工智能领域知名科学家、Landing.ai 创始人兼 CEO 吴恩达&#xff08;Andrew Ng&#xff09;与 LG&#xff08;LG Electronics&#xff09;总裁兼 CTO IP. Park 在拉斯维加斯签署了战略合作伙…

linux上安装mysql,tomcat,jdk

Linux 上安装 1 安装jdk 检测是否安装了jdk 运行 java –version若有 需要将其卸载a) 查看安装哪些jdk rmp –qa |grep java b) 先卸载openjdk 1.7 c) 在卸载openjdk 1.6 使用rpm –e - -nodeps 卸载的包 安装jdka) 上传jdk到linux 使用Xftp5…

现代人的无知什么样

以前没有知识的人就是无知&#xff01; 但现在变了&#xff01;一个博士却不会用他的知识挣钱养家糊口算不算无知&#xff0c;一个人大学毕业却不会学习算不算无知&#xff0c;一个经理在自己的电脑上找不到自己存的东西算不算无知&#xff0c;有知识却不会表达的人算不算无知…

zz Expect的安装

转载一篇靠谱的文章&#xff0c;按照文章所述方法一次成功。只不过我的expect二进制文件最后实在tcl的bin目录下&#xff0c;而不是expect的bin目录下&#xff0c;这个令我有些疑惑&#xff0c;whatever&#xff0c;不算什么大问题&#xff0c;注意一下就好了。A. Tcl 安装 主页…

分享一个ssh打通的脚本

分享一个ssh打通的脚本&#xff0c;经过测试可用。目前只能单向打通&#xff0c;且要求本地用户名为admin(写入代码&#xff0c;可简单修改)。本身只是个人使用&#xff0c;故通用性、异常情况考虑不多&#xff0c;大家可以做个参考。 补充一点&#xff0c;Important Tip&…

从云计算到AI:NetApp的数据网络转型之道

毫无疑问&#xff0c;在 AI、大数据、云计算等新技术潮流的冲击下&#xff0c;各行业企业的数字化转型进程日益加速&#xff0c;社会正在进入一个全新的数据融合时代。这一过程中&#xff0c;人们一方面对技术予以高期待&#xff0c;期望给行业进行业务重构&#xff0c;但另一方…

侧方位停车技巧

侧方位停车技巧 侧方位停车相对来说是比较容易的&#xff0c;只要掌握要领就能够正确地倒入车位中。具体要领如下&#xff1a; 第一步先打右转向灯&#xff0c;挂倒档&#xff0c;保持车辆平稳、缓慢地倒车&#xff1b;第二步回头看桩&#xff0c;当右后车门三角窗中部与1号桩&…

微信是把“杀猪刀”,还改变了我的表情包

整理 | Jane出品 | Python大本营1 月 9 日上午&#xff0c;一年一度的微信公开课 PRO 在广州举行&#xff0c;会上发布了《2018微信年度数据报告》。报告的第一部分是 2018 年微信用户活跃数、发送消息与音视频通话数据&#xff1b;第二部分根据微信用户画像&#xff0c;针对不…

中缀、前缀表达式

为什么80%的码农都做不了架构师&#xff1f;>>> 一、后缀表达式求值 后缀表达式也叫逆波兰表达式&#xff0c;其求值过程可以用到栈来辅助存储。假定待求值的后缀表达式为&#xff1a;6 5 2 3 8 * 3 *&#xff0c;则其求值过程如下&#xff1a; 1&#xf…

Linux之tee命令

语  法&#xff1a;tee [-ai][--help][--version][文件...]补充说明&#xff1a;tee指令会从标准输入设备读取数据&#xff0c;将其内容输出到标准输出设备&#xff0c;同时保存成文件。参  数&#xff1a;-a或--append  附加到既有文件的后面&#xff0c;而非覆盖它&…

在WinXP上通过Virtual PC安装WinCE

开发WinCE程序的调试&#xff0c;要么用Emulator&#xff0c;要么用触摸屏等等硬件&#xff0c;模拟器不真实&#xff0c;硬件又难找还不易随身带。象我这样穷得买不了带CE的PDA&#xff0c;懒得不想下巨型的PB、VS&#xff0c;要随时调试还真不容易。试过VMWare&#xff0c;效…

valgrind概述及错误分析

Valgrind由内核&#xff08;core&#xff09;以及基于内核的其他调试工具组成.内核类似于一个框架&#xff08;framework&#xff09;,它模拟了一个CPU环境,并提供服务给其他工具.而其他工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的内存调试任务。 Valgrind包…

超过C++、压制Java与C,Python拔得TIOBE年度编程语言!

作者 | 屠敏来源 | CSDN&#xff08;ID&#xff1a;CSDNNews&#xff09;如同两个月前&#xff0c;TIOBE 编程语言社区于官网预料的那般&#xff0c;2018 年的年度编程语言终将在一众老牌编程语言如 Java、C、C、Python、Visual Basic .NET 中诞生。近日&#xff0c;TIOBE 排行…

CodeArt SharePoint Permission Extension 1.0 beta publish

正式发布1.0版本&#xff0c;已经打包成wsp&#xff0c;请到以下地址下载&#xff1a;http://sppex.codeplex.com/Release/ProjectReleases.aspx?ReleaseId30671 解压后&#xff0c;运行wsp_addsolution.cmd安装解决方案&#xff0c;到管理中心-》操作-》解决方案管理安装解决…

《请不要回应外星人2019》

作者 | 若名出品 | AI科技大本营 今天早上&#xff0c;关于“加拿大天文学家发现 15 亿光年外讯号”的话题一度被推到了微博热搜榜第二位&#xff0c;当然也引发了全球范围内的关注。舆论导向都是&#xff0c;“人类该不该做出回应&#xff1f;”翻了一圈评论&#xff0c;人…

如何使用Log4j?

要学习什么是log4j,那我们也知道log4j能干吗??这里就不阐述了,可以自己去google1、 Log4j是什么&#xff1f; Log4j可以帮助调试&#xff08;有时候debug是发挥不了作 用的&#xff09;和分析&#xff0c;要下载和了解更详细的内容&#xff0c;还是访问其官方网站吧&#xf…

解决:无法创建该DNS 服务器的委派

第一次安装AD DNS的时候&#xff0c;你可能遇到以下的提示&#xff0c;无法创建该DNS 服务器的委派&#xff0c;这是一个提示&#xff0c;而不是一个报错。 以下是详细的说明。 将具有 DNS 服务器的新 Windows Server 2008 或 Windows Server 2008 R2 域控制器安装到 treyr…

SQL to Elasticsearch java code

把Elasticsearch当成Database用&#xff0c;因为Elasticsearch不支持SQL&#xff0c;就需要把SQL转换成代码实现。 1.按某个field group by查询count SELECT fieldA, COUNT(fieldA) from table WHERE fieldC "hoge" AND fieldD "huga" AND fieldB…

【转载】linux静态链接库与动态链接库的区别及动态库的创建

这篇文章对于动态库的概念及使用介绍的很不错&#xff0c;故收藏了。一、引言通常情况下&#xff0c;对函数库的链接是放在编译时期&#xff08;compile time&#xff09;完成的。所有相关的对象文件&#xff08;object file&#xff09;与牵涉到的函数库&#xff08;library&a…

买不到回家的票,都是“抢票加速包”惹的祸?

作者 | 屠敏来源 | CSDN&#xff08;ID&#xff1a;CSDNNews&#xff09;距离国家法定春节假日不足一个月&#xff0c;且首批除夕票已于近日正式开售。但万万没想到&#xff0c;当人、钱、手机、PC、iPad 万事俱备之际&#xff0c;东风刮得太快&#xff0c;眼巴巴盯着将于整点开…

HTSRealistic missions 10:Holy Word High School

这到题说实在的挺难。。。首先进入页面&#xff0c;进去后查看源代码发现有个空图片&#xff0c;图片是个链接&#xff0c;链接到staff.php。点击进入要求用户名密码&#xff0c;尝试注入&#xff0c;无效在来至主页&#xff0c;有个staff list的链接&#xff0c;点进去&#x…

Makefile的东西

宏定义&#xff1a; 1. Makefile中直接定义宏 OBJECTSfilea.o fileb.o filec.o #定义宏 Zfiled.oprog: $(OBJECTS) #引用宏cc $(OBJECTS) -o prog #我的机子环境中需要4个tab键prog1: $Z #引用宏&#xff0c;单个字符无需加园括号cc $Z -o prog12. 在make命令之后带有新的宏定…

TensorFlow 2.0开发者预览版发布

整理 | Jane出品 | AI科技大本营从去年 8 月 Google 公开发布消息正在研发 TensorFlow 2.0 &#xff0c;让我们在 12 月 提前看到了一些 高级 API 的变化&#xff0c;今天我们终于等来了“tf-nightly-2.0”&#xff0c;一个 TensorFlow 2.0 开发者预览版。在今天 Wicke 的邮件中…

DOCKER OVERLAY NETWORK consul 注册

下载 consul 二进制包并启动 wget https://releases.hashicorp.com/consul/0.9.2/consul_0.9.2_linux_amd64.zip unzip consul_0.9.2_linux_amd64.zip mv consul /usr/bin/consul && chmod x /usr/bin/consul nohup consul agent -server -bootstrap -ui -data-dir /va…

怎么写shell脚本才能不耍流氓?

1、不记录日志的 SHELL 脚本就是耍流氓&#xff01; 我们经常在工作中会遇到一个苦恼的事情&#xff0c;一个 Shell 脚本到底干了什么&#xff0c;什么时候开始执行&#xff0c;什么时候结束的。尤其是数据库备份&#xff0c;我们想知道我们的 MySQL 数据库备份时间。所以给脚本…

透过腾讯张潼离职事件,看AI研究院如何才算成功?

作者 | 洪亮劼编辑 | 琥珀【AI科技大本营导读】近日腾讯 AI Lab 第一负责人张潼博士的离职事件&#xff0c;让不少圈内人士对企业 AI 研究院/实验室的定位、落地能力等问题进行了深刻思考和讨论。据最新消息&#xff0c;张潼未来将回到学界&#xff0c;继续 AI 领域的学术研究&…

java vs .net

... vs paramsjavaprivatestaticintsumUp(int... values) { intsum 0; for(inti 0; i < values.length; i) { sum values[i]; } returnsum; } .netparams 关键字在方法成员的参数列表中使用&#xff0c;为该方法提供了参数个数可变的能力它在只能出现一次并…