原文地址:https://medium.com/rocknnull/effective-java-for-android-cheatsheet-bf4e3433889a#.ksxu4xb86
《Effective Java》被认为是关于编写可维护的稳定且有效Java代码的最重要的书籍之一。Android使用的是Java,这就意味着所有书中所有的建议都适用,对吗?不一定。一些人认为大多数书中的建议都不适用于Android的开发环境。在我看来,事情并非如此。我相信书中的部分内容是不适用的,毕竟不是所有的Java特性都在Android中得到了充分利用(比如enums, serialization等),或者是因为移动设备的限制(比如:Dalvik/ART就和JVM不同)。无论如何,大多数书中的范例可以小幅或不用修改即可使用,并且可以变的更加健壮,简洁,更加可维护。
这篇文章会集中阐述我认为在开发Android app时,书中最重要的部分。对于那些读过此书的人,这篇文章会让你回忆起书中提到的内容或原则。对于还未阅读过的人来说,这可以让他们了解此书所提供的内容。
强制不可实例化
如果你不想让对象可以通过新的关键字创建,那么强制它使用一个私有的构造函数。
对于只包含静态方法的工具类来讲格外有用。
class MovieUtils {
private MovieUtils() {}
static String titleAndYear(Movie movie) {
[...]
}
}
静态工厂
替代使用新关键字,构造函数使用静态工厂方法(和一个私有构造函数)。
class Movie {
[...]
public static Movie create(String title) {
return new Movie(title);
}
}
创建者
当你的对象需要三个以上构造函数参数时,使用创建者来构建对象。它书写起来可能会有一点冗长,但是它可扩,可读性好。如果你在创建值类,考虑下自动值。
class Movie {
static Builder newBuilder() {
return new Builder();
}
static class Builder {
String title;
Builder withTitle(String title) {
this.title = title;
return this;
}
Movie build() {
return new Movie(title);
}
}
private Movie(String title) {
[...]
}
}
// Use like this:
Movie matrix = Movie.newBuilder().withTitle("The Matrix").build();
避免易变
不可变是一个对象在它的整个生命周期内保持相同。所有对象必要的数据在它创建时就被提供。这种方式有许多的优点,比如简单,线程安全和可分享。
class Movie {
[...]
Movie sequel() {
return Movie.create(this.title + " 2");
}
}
// Use like this:
Movie toyStory = Movie.create("Toy Story");
Movie toyStory2 = toyStory.sequel();
让所有类不可变可能会很困难。如果可以,尽量让你的类不可变(比如,private final字段和final类)。对象的创建在手机上更加花费资源,因此不要过度使用。
静态成员类
如果你定义了一个不依赖外部类的内部类,不要忘了将它定成了静态类。
class Movie {
[...]
static class MovieAward {
[...]
}
}
(几乎)无处不在的泛型
Java是类型安全的,我们需要感谢这一点(看看JS)。尽可能的避免使用不确定的类型或Object类型。大多数时候,泛型的提供令你的代码在编译时是类型安全的。
// DON'T
List movies = Lists.newArrayList();
movies.add("Hello!");
[...]
String movie = (String) movies.get(0);
// DO
List<String> movies = Lists.newArrayList();
movies.add("Hello!");
[...]
String movie = movies.get(0);
不要忘了你可以在你的方法和返回值中使用泛型。
// DON'T List sort(List input) {
[...]
}
// DO <T> List<T> sort(List<T> input) {
[...]
}
想要更加灵活,你可以使用通配符来扩展你可以接受的类型范围。
// Read stuff from collection - use "extends"
void readList(List<? extends Movie> movieList) {
for (Movie movie : movieList) {
System.out.print(movie.getTitle());
[...]
}
}
// Write stuff to collection - use "super"
void writeList(List<? super Movie> movieList) {
movieList.add(Movie.create("Se7en"));
[...]
}
返回空
当我们返回一个列表或集合时,使用无结果而非null。返回一个空集合使得接口更简单(不需要文档或注释null返回方法),并且避免了空指针异常。最好是返回相同的空集合而非创建一个新的。
List<Movie> latestMovies() {
if (db.query().isEmpty()) {
return Collections.emptyList();
}
[...]
}
不要加字符串
必须要连接多个字符串,+操作符可能可以。但永远不要使用它来连接大量字符串;性能会非常差。最好使用StringBuilder来替代。
String latestMovieOneLiner(List<Movie> movies) {
StringBuilder sb = new StringBuilder();
for (Movie movie : movies) {
sb.append(movie);
}
return sb.toString();
}
回收异常
我不赞成用抛出异常来表明错误,但是如果你这么做了,确保异常经过检查,并且异常的接收者可以回收这些错误。
List<Movie> latestMovies() throws MoviesNotFoundException {
if (db.query().isEmpty()) {
throw new MoviesNotFoundException();
}
[...]
}
结尾
这个列表并不是书中所提及的全部建议列表,短短的文字也不能充分的解释。这更像是一个实用技巧的小抄。