设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

适用于Android开发的Effective Java

2017-3-19 18:47| 发布者: joejoe0332| 查看: 369| 评论: 0|原作者: Tocy, 边城|来自: oschina

摘要: “Effective Java” 被许多人看做是编写高效且可维护的 Java 代码的重要指导书之一。Android 使用 Java 开发是否意味着里面的建议都要用上?不完全是。 有些人认为这本书给出的大多数建议不适用于 Android 开发。在 ...
Effective Java” 被许多人看做是编写高效且可维护的 Java 代码的重要指导书之一。Android 使用 Java 开发是否意味着里面的建议都要用上?不完全是。 有些人认为这本书给出的大多数建议不适用于 Android 开发。在我看来,情况并非如此。 我认为这本书的一些部分是不适用,不管是因为不是所有 Java 功能都已优化到能与 Android 一起使用(例如枚举、序列化等),还是因为是移动设备的限制例如 Dalvik/ART 表现不同于桌面版的 JVM)。 但不管怎样,本书中的大多数范式还是可以在稍作修改后或直接使用,从而构建一个更健康、更简洁和更易维护的代码库。

这篇博客整合了我在开发 Android 应用时,从 Effective Java 中学习到的重要内容。对于那些读过这本书的人,这篇文章就当是重新回顾一下,对于那些(还)没有阅读它的人,可以把这篇文章当作试读。

强制非实例化(non-instantiability)

如果你不想使用 new 关键字来创建对象,强制它使用私有构造函数。 这对那些仅包含静态函数的工具类尤其有用。

class MovieUtils {
    private MovieUtils() {}    static String titleAndYear(Movie movie) {
        [...]
    }
}

静态工厂

用静态工厂方法 (同时私有化构造器) 代替使用 new 和构造函数。这些工厂方法有自己的名称,不需要每次都返回一个对象的新实例,还可以根据需要返回不同的子对象。

class Movie {
    [...]
    public static Movie create(String title) {
        return new Movie(title);
    }
}

[更新] 我们的读者 @stsdema28 提供了一个有用的提示:静态工厂方法会造成测试困难。如果遇到这种问题,需要使用在测试中使用可模拟的非静态工厂(或者一个可实现的假接口)。

构建器(Builder)

如果你的对象需要超过 3 个构造参数,那就使用构建器来构造对象。这写起来可能有点繁琐,但它扩展性良好而且容易看明白。如果你要创建值类,可以考虑 AutoValue

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 字段和 private class)。在移动端创建对象开销很大,所以注意不要过度创建。

静态成员类

如果你定义了一个不依赖于外部类的内部类,千万别忘了把它定义成静态的。如果不这样做,会导致每个内部类的实例都持有外部类的引用。

class Movie {
    [...]
    static class MovieAward {
        [...]
    }
}

随处可见的泛型

Java 提供了类型安全支持。尽量避免使用原始类型或对象类型。在大多数情况下,泛型提供了编译时让代码类型安全的机制。

// 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) {
    [...]
}

为获得更佳的灵活性,你可以使用有界通配符(bounded wildcards)来扩展可接受类型的范围。

// 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"));
    [...]
}

返回空值

当必须返回空的 list/collection 时避免使用 null。返回空的集合会使接口变简单(不需要为空返回的函数写文档或注释)并可以避免随机的 NPE。建议返回同一个空集合而不是重新创建一个。

List<Movie> latestMovies() {
    if (db.query().isEmpty()) {
        return Collections.emptyList();
    }
    [...]
}

不要使用 + String 操作

要连接几个字符串时,+ 操作也许可行。但不要将其用于大量字符串的连接,这样性能很糟糕。建议用 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();
    }
    [...]
}

结论

这个列表并没有罗列书中的所有建议,也不是对书中某个建议的深度解析,而仅仅是对部分有用建议的摘录而已。


酷毙

雷人

鲜花

鸡蛋

漂亮

最新评论

(200字以内)
验证问答 换一个 验证码 换一个

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187  

返回顶部