Google GitHub托管的项目AutoValue之所以有趣,有多种原因。 该项目不仅使为“ 值对象 ”编写更少的Java代码变得容易,而且还为Java注释处理的实际应用提供了概念上简单的演示。 该自动/值项目是由提供谷歌的员工凯文Bourrillion和埃蒙·麦克马纳斯和许可与Apache的版本2的许可 。
《 AutoValue用户指南》简短明了,其简洁性反映了项目本身。 用户指南提供了使用AutoValue的简单示例,讨论了为什么需要 AutoValue,在“ 我如何……”部分中回答了常见问题,并概述了与使用AutoValue有关的一些最佳做法 。
以下代码清单包含一个我手写的简单类,称为Person
。 编写此类时要牢记AutoValue。
人.java
package dustin.examples.autovalue;
import com.google.auto.value.AutoValue;
/**
* Represents an individual as part of demonstration of
* GitHub-hosted project google/auto/value
* (see https://github.com/google/auto/tree/master/value).
*/
@AutoValue // concrete extension will be generated by AutoValue
abstract class Person
{
/**
* Create instance of Person.
*
* @param lastName Last name of person.
* @param firstName First name of person.
* @param birthYear Birth year of person.
* @return Instance of Person.
*/
static Person create(String lastName, String firstName, long birthYear)
{
return new AutoValue_Person(lastName, firstName, birthYear);
}
/**
* Provide Person's last name.
*
* @return Last name of person.
*/
abstract String lastName();
/**
* Provide Person's first name.
*
* @return First name of person.
*/
abstract String firstName();
/**
* Provide Person's birth year.
*
* @return Person's birth year.
*/
abstract long birthYear();
}
当使用AutoValue生成完整的“值类”时,只需为AutoValue提供一个抽象类(故意不支持接口)以生成相应的具体扩展。 该abstract
类必须使用@AutoValue
注释进行注释,必须提供提供值类实例的static
方法,并且必须提供暗示值类的受支持字段的public
或包范围的abstract
访问器方法。
在上面的代码清单中,静态实例创建方法实例化了AutoValue_Person
对象,但是我没有定义这样的AutoValue_Person
类。 此类是AutoValue生成的类的名称,该类将在对Person.java
进行javac编译时执行AutoValue的注释处理时生成。 由此,我们可以看到AutoValue生成的类的命名约定: AutoValue_
放在源类的名称之前,以形成生成的类的名称。
当Person.java
在编译过程中应用AutoValue注释处理进行编译时,将生成生成的类。 就我而言(使用AutoValue 1.2 / auto-value-1.2.jar
),生成了以下代码:
AutoValue_Person.java:由AutoValue生成
package dustin.examples.autovalue;
import javax.annotation.Generated;
@Generated("com.google.auto.value.processor.AutoValueProcessor")
final class AutoValue_Person extends Person {
private final String lastName;
private final String firstName;
private final long birthYear;
AutoValue_Person(
String lastName,
String firstName,
long birthYear) {
if (lastName == null) {
throw new NullPointerException("Null lastName");
}
this.lastName = lastName;
if (firstName == null) {
throw new NullPointerException("Null firstName");
}
this.firstName = firstName;
this.birthYear = birthYear;
}
@Override
String lastName() {
return lastName;
}
@Override
String firstName() {
return firstName;
}
@Override
long birthYear() {
return birthYear;
}
@Override
public String toString() {
return "Person{"
+ "lastName=" + lastName + ", "
+ "firstName=" + firstName + ", "
+ "birthYear=" + birthYear
+ "}";
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof Person) {
Person that = (Person) o;
return (this.lastName.equals(that.lastName()))
&& (this.firstName.equals(that.firstName()))
&& (this.birthYear == that.birthYear());
}
return false;
}
@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= this.lastName.hashCode();
h *= 1000003;
h ^= this.firstName.hashCode();
h *= 1000003;
h ^= (this.birthYear >>> 32) ^ this.birthYear;
return h;
}
}
通过检查生成的代码可以得出以下几点结论:
- 生成的类扩展(实现继承)了手写的抽象类,从而允许使用代码使用手写类的API,而不必知道正在使用生成的类。
- 即使没有在源类中直接定义任何字段,也将生成字段; AutoValue解释了提供的
abstract
访问器方法中的字段。 - 生成的类不为字段提供“设置” / mutator方法(get / accessor方法)。 这是AutoValue的故意设计决策 ,因为Value Objects的关键概念是它们是不可变的。
- 考虑到每个字段的类型,将自动为每个字段适当地生成equals(Object) , hashCode()和toString()的实现。
- 在源类和方法上的Javadoc注释不会在生成的扩展类上重现。
使用诸如AutoValue生成之类的方法的主要优点之一是,开发人员可以专注于特定类应支持的更高级的概念,并且代码生成可确保一致且正确地实现较低级别的细节。 但是,使用这种方法时需要牢记一些注意事项,该文档的“ 最佳实践”部分是一个不错的地方,可以让您早日阅读一下以了解AutoValue的假设是否适合您的情况。
- 当开发人员受过足够的训练以查看和维护
abstract
“源” Java类而不是生成的类时,AutoValue最有可能会有所帮助。- 下次注释处理再次生成该类时,对生成类的更改将被覆盖,否则必须停止该类的生成,以免发生这种情况。
- 您将需要设置build / IDE,以便将生成的类视为“源代码”,以便
abstract
类可以编译。 - 如果将可变字段与AutoValue一起使用时,如果要保持不变性,则必须格外小心(通常选择使用Value Objects时就是这种情况)。
- 查看“ 最佳实践”和“我如何……”部分,以确保没有任何AutoValue的设计假设使它不利于您的需求。
结论
AutoValue允许开发人员编写更简洁的代码,重点放在高级细节上,并将繁琐的低级(通常是容易出错的)细节的实现委派给AutoValue,以自动生成代码。 这类似于IDE的源代码生成可以执行的操作,但是AutoValue相对于IDE方法的优势在于,AutoValue可以在每次编译代码时重新生成源代码,从而使生成的代码保持最新。 AutoValue的这一优势也是Java自定义注释处理功能强大的一个很好的例子。
翻译自: https://www.javacodegeeks.com/2016/06/autovalue-generated-immutable-value-classes.html