《Effective Java 第三版》——第二章 创建和销毁对象

《Effective Java 第三版》目录汇总

 

经过反复不断的拖延和坚持,所有条目已经翻译完成,供大家分享学习。时间有限,个别地方翻译得比较仓促,希望有疑虑的地方指出批评改正。

第一章简介

忽略

第二章 创建和销毁对象

1. 考虑使用静态工厂方法替代构造方法
2. 当构造方法参数过多时使用builder模式
3. 使用私有构造方法或枚类实现Singleton属性
4. 使用私有构造方法执行非实例化
5. 使用依赖注入取代硬连接资源
6. 避免创建不必要的对象
7. 消除过期的对象引用
8. 避免使用Finalizer和Cleaner机制
9. 使用try-with-resources语句替代try-finally语句

第三章 所有对象的通用方法

10. 重写equals方法时遵守通用约定
11. 重写equals方法时同时也要重写hashcode方法
12. 始终重写 toString 方法
13. 谨慎地重写 clone 方法
14.考虑实现Comparable接口

第四章 类和接口

15. 使类和成员的可访问性最小化
16. 在公共类中使用访问方法而不是公共属性
17. 最小化可变性
18. 组合优于继承
19. 如果使用继承则设计,并文档说明,否则不该使用
20. 接口优于抽象类
21. 为后代设计接口
22. 接口仅用来定义类型
23. 优先使用类层次而不是标签类
24. 优先考虑静态成员类
25. 将源文件限制为单个顶级类

第五章 泛型

26. 不要使用原始类型
27. 消除非检查警告
28. 列表优于数组
29. 优先考虑泛型
30. 优先使用泛型方法
31. 使用限定通配符来增加API的灵活性
32. 合理地结合泛型和可变参数
33. 优先考虑类型安全的异构容器

第六章 枚举和注解

34. 使用枚举类型替代整型常量
35. 使用实例属性替代序数
36. 使用EnumSet替代位属性
37. 使用EnumMap替代序数索引
38. 使用接口模拟可扩展的枚举
39. 注解优于命名模式
40. 始终使用Override注解
41. 使用标记接口定义类型

第七章 Lambda表达式和Stream流

42. lambda表达式优于匿名类
43. 方法引用优于lambda表达式
44. 优先使用标准的函数式接口
45. 明智审慎地使用Stream
46. 在流中优先使用无副作用的函数
47. 优先使用Collection而不是Stream来作为方法的返回类型
48. 谨慎使用流并行

第八章 方法

49. 检查参数有效性
50. 必要时进行防御性拷贝
51. 仔细设计方法签名
52. 明智而审慎地使用重载
53. 明智而审慎地使用可变参数
54. 返回空的数组或集合不要返回null
55. 明智而审慎地返回Optional
56. 为所有已公开的API元素编写文档注释

第九章 通用编程

57. 最小化局部变量的作用域
58. for-each循环优于传统for循环
59. 熟悉并使用Java类库
60. 需要精确的结果时避免使用float和double类型
61. 基本类型优于装箱的基本类型
62. 当有其他更合适的类型时就不用字符串
63. 注意字符串连接的性能
64. 通过对象的接口引用对象
65. 接口优于反射
66. 明智谨慎地使用本地方法
67. 明智谨慎地进行优化
68. 遵守普遍接受的命名约定

第十章 异常

69. 仅在发生异常的条件下使用异常
70. 对可恢复条件使用已检查异常,对编程错误使用运行时异常
71. 避免不必要地使用检查异常
72. 赞成使用标准异常
73. 抛出合乎于抽象的异常
[74. 文档化每个方法抛出的所有异常]https://www.cnblogs.com/IcanFixIt/p/10631106.html)
75. 在详细信息中包含失败捕获信息
76. 争取保持失败原子性
77. 不要忽略异常

第十一章 并发

78. 同步访问共享的可变数据
79. 避免过度同步
80. EXECUTORS, TASKS, STREAMS 优于线程
81. 优先使用并发实用程序替代wait和notify
82. 线程安全文档化
83. 明智谨慎地使用延迟初始化
84. 不要依赖线程调度器

第十二章 序列化

85. 其他替代方式优于Java本身序列化
86. 非常谨慎地实现SERIALIZABLE接口
87. 考虑使用自定义序列化形式
88. 防御性地编写READOBJECT方法
89. 对于实例控制,枚举类型优于READRESOLVE
90. 考虑序列化代理替代序列化实例

第三版全。下回再见,后会有期!

 

 

 

享元模式:

线程不安全

所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。

共享模式是支持大量细粒度对象的复用,所以享元模式要求能够共享的对象必须是细粒度对象。

在了解享元模式之前我们先要了解两个概念:内部状态、外部状态。

内部状态:在享元对象内部不随外界环境改变而改变的共享部分。

外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。

由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。在我们的程序设计过程中,我们可能会需要大量的细粒度对象来表示对象,如果这些对象除了几个参数不同外其他部分都相同,这个时候我们就可以利用享元模式来大大减少应用程序当中的对象。如何利用享元模式呢?这里我们只需要将他们少部分的不同的部分当做参数移动到类实例的外部去,然后再方法调用的时候将他们传递过来就可以了。这里也就说明了一点:内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。

可知享元模式为我们节省了很多的内存空间,省去了不必要的内存资源浪费。
在上面的定义中我们看到【内部状态】【外部状态】的定义,此处在高并发的情况应该不是线程安全的,比如,同一时间2个线程获取同一个对象,然后分别赋予不同的外部状态,这个时候就可能出现不安全的因素
————————————————

 

享元模式

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。

享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。我们将通过创建 5 个对象来画出 20 个分布于不同位置的圆来演示这种模式。由于只有 5 种可用的颜色,所以 color 属性被用来检查现有的 Circle 对象。

介绍

意图:运用共享技术有效地支持大量细粒度的对象。

主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

关键代码:用 HashMap 存储这些对象

应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的数据池。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。

注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。

 

 

 桥接模式:把另一个维度(以接口引用的形式)注入进来(下面两例中的:DrawAPI、ICoffeeAdditives)

https://www.runoob.com/design-pattern/bridge-pattern.html

https://zhuanlan.zhihu.com/p/58903776

 

package effectivejava.chapter2.item2.javabeans;

// JavaBeans Pattern - allows inconsistency, mandates mutability  (pages 11-12)
public class NutritionFacts {
    // Parameters initialized to default values (if any)
    private int servingSize  = -1; // Required; no default value
    private int servings     = -1; // Required; no default value
    private int calories     = 0;
    private int fat          = 0;
    private int sodium       = 0;
    private int carbohydrate = 0;

    public NutritionFacts() { }
    // Setters
    public void setServingSize(int val)  { servingSize = val; }
    public void setServings(int val)     { servings = val; }
    public void setCalories(int val)     { calories = val; }
    public void setFat(int val)          { fat = val; }
    public void setSodium(int val)       { sodium = val; }
    public void setCarbohydrate(int val) { carbohydrate = val; }

    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts();
        cocaCola.setServingSize(240);
        cocaCola.setServings(8);
        cocaCola.setCalories(100);
        cocaCola.setSodium(35);
        cocaCola.setCarbohydrate(27);
    }
}
JavaBeans
package effectivejava.chapter2.item2.telescopingconstructor;

// Telescoping constructor pattern - does not scale well! (Pages 10-11)
public class NutritionFacts {
    private final int servingSize;  // (mL)            required
    private final int servings;     // (per container) required
    private final int calories;     // (per serving)   optional
    private final int fat;          // (g/serving)     optional
    private final int sodium;       // (mg/serving)    optional
    private final int carbohydrate; // (g/serving)     optional

    public NutritionFacts(int servingSize, int servings) {
        this(servingSize, servings, 0);
    }

    public NutritionFacts(int servingSize, int servings,
                          int calories) {
        this(servingSize, servings, calories, 0);
    }

    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat) {
        this(servingSize, servings, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium) {
        this(servingSize, servings, calories, fat, sodium, 0);
    }
    public NutritionFacts(int servingSize, int servings,
                          int calories, int fat, int sodium, int carbohydrate) {
        this.servingSize  = servingSize;
        this.servings     = servings;
        this.calories     = calories;
        this.fat          = fat;
        this.sodium       = sodium;
        this.carbohydrate = carbohydrate;
    }

    public static void main(String[] args) {
        NutritionFacts cocaCola =
                new NutritionFacts(240, 8, 100, 0, 35, 27);
    }
    
}
TelescopingConstructor
package effectivejava.chapter2.item2.builder;

// Builder Pattern  (Page 13)
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories      = 0;
        private int fat           = 0;
        private int sodium        = 0;
        private int carbohydrate  = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings    = servings;
        }

        public Builder calories(int val)
        { calories = val;      return this; }
        public Builder fat(int val)
        { fat = val;           return this; }
        public Builder sodium(int val)
        { sodium = val;        return this; }
        public Builder carbohydrate(int val)
        { carbohydrate = val;  return this; }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder) {
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }

    public static void main(String[] args) {
        NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)
                .calories(100).sodium(35).carbohydrate(27).build();
    }
}

  

package effectivejava.chapter2.item2.hierarchicalbuilder;
import java.util.*;

// Builder pattern for class hierarchies (Page 14)

// Note that the underlying "simulated self-type" idiom  allows for arbitrary fluid hierarchies, not just builders

public abstract class Pizza {
    public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE }
    final Set<Topping> toppings;

    abstract static class Builder<T extends Builder<T>> {
        //EnumSet.noneOf: Creates an empty enum set with the specified element type.
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }

        abstract Pizza build();

        // Subclasses must override this method to return "this"
        protected abstract T self();
    }
    
    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone(); // See Item 50
    }
}
package effectivejava.chapter2.item2.hierarchicalbuilder;

import static effectivejava.chapter2.item2.hierarchicalbuilder.Pizza.Topping.*;
import static effectivejava.chapter2.item2.hierarchicalbuilder.NyPizza.Size.*;

// Using the hierarchical builder (Page 16)
public class PizzaTest {
    public static void main(String[] args) {
        NyPizza pizza = new NyPizza.Builder(SMALL)
                .addTopping(SAUSAGE).addTopping(ONION).build();
        Calzone calzone = new Calzone.Builder()
                .addTopping(HAM).sauceInside().build();
        
        System.out.println(pizza);
        System.out.println(calzone);
    }
}
package effectivejava.chapter2.item2.hierarchicalbuilder;

import java.util.Objects;

// Subclass with hierarchical builder (Page 15)
public class NyPizza extends Pizza {
    public enum Size { SMALL, MEDIUM, LARGE }
    private final Size size;

    //public static class NyPizza.Builder extends Pizza.Builder<NyPizza.Builder>
    public static class Builder extends Pizza.Builder<Builder> {
        private final Size size;

        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }

        @Override public NyPizza build() {
            return new NyPizza(this);
        }

        @Override protected Builder self() { return this; }
    }

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }

    @Override public String toString() {
        return "New York Pizza with " + toppings;
    }
}
package effectivejava.chapter2.item2.hierarchicalbuilder;

// Subclass with hierarchical builder (Page 15)
public class Calzone extends Pizza {
    private final boolean sauceInside;

    public static class Builder extends Pizza.Builder<Builder> {
        private boolean sauceInside = false; // Default

        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }

        @Override public Calzone build() {
            return new Calzone(this);
        }

        @Override protected Builder self() { return this; }
    }

    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }

    @Override public String toString() {
        return String.format("Calzone with %s and sauce on the %s",
                toppings, sauceInside ? "inside" : "outside");
    }
}

Java 泛型中如何实现 Self?

KiKi:Java 中没有 const?​zhuanlan.zhihu.com

上面的文章提到我们要实现编译期的 immutable view 的第一步是分离 const 和 non-const 的方法

也就是说 所有方法要么是 const 的要么是 non-const 的

那么 copy 呢?

很显然这是一个 const 方法 因为它并不会改变内部数据

不过 copy 的返回值类型应该是什么呢?

难道是 ImmutableFoo?

interface ImmutableFoo {
    ImmutableFoo copy();
}

很显然不够好

因为这让我们 copy 的返回对象无法修改

实际上我们想要的是什么?

没错是 Foo 也就是最终实现这个接口的类的类型

在 swift rust 的泛型中有一个特殊类型叫做 Self 就是表示这种情况的

而 Java 中很遗憾并没有这个东西

不过我们可以写一个泛型参数

让使用者把实际类型写进去

interface ImmutableFoo<Self> {
    Self copy();
}

但是很明显这个不够安全

因为使用者可以把 Self 写成任意类型

为了让 Self 更安全

我们给 Self 添加一些约束条件

大家仔细想就能知道 Self 一定是 Immutable<Self> 这是一个递归定义

所以我们可以这么改进

interface ImmutableFoo<Self extends Immutable<Self>> {
    Self copy();
}

然后我们就能开心的这写了

class Foo implements Immutable<Foo> {
    @Override
    public Foo copy() {...} //注意这里是Foo哦
}

此时如果把 Self 写成其他类型 比如 Integer 是会出现编译错误的

但这样就完美了么

不 它不完美

它并不能阻止你这样做

class Bar implements Immutable<Bar> {...}

class Foo implements Immutable<Bar> {...} //注意这里 写了Bar 编译并不会出问题

在此就只能希望 Java 泛型也能加入 Self 类型

 
   

 

simulated self-type:

// Subclasses must override this method to return "this"
protected abstract T self();
子类:
@Override protected Builder self() { return this; }

协变返回类型:

abstract Pizza build();

子类:
@Override public NyPizza build() {
    return new NyPizza(this);
}


条目3:

static factory:

package effectivejava.chapter2.item3.staticfactory;

// Singleton with static factory (Page 17)
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { }
    public static Elvis getInstance() { return INSTANCE; }

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.getInstance();
        elvis.leaveTheBuilding();
    }
}
static factory

field:

package effectivejava.chapter2.item3.field;

// Singleton with public final field  (Page 17)
public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() { }

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}
field

enum type:

package effectivejava.chapter2.item3.enumtype;

// Enum singleton - the preferred approach (Page 18)
public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}
enum type

条目4:

package effectivejava.chapter2.item4;

// Noninstantiable utility class (Page 19)
public class UtilityClass {
    // Suppress default constructor for noninstantiability
    private UtilityClass() {
        throw new AssertionError();
    }

    // Remainder omitted
}

条目6:

package effectivejava.chapter2.item6;
import java.util.regex.Pattern;

// Reusing expensive object for improved performance (Pages 22 and 23)
public class RomanNumerals {
    // Performance can be greatly improved! (Page 22)
    static boolean isRomanNumeralSlow(String s) {
        return s.matches("^(?=.)M*(C[MD]|D?C{0,3})"
                + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
    }

    // Reusing expensive object for improved performance (Page 23)
    private static final Pattern ROMAN = Pattern.compile(
            "^(?=.)M*(C[MD]|D?C{0,3})"
                    + "(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");

    static boolean isRomanNumeralFast(String s) {
        return ROMAN.matcher(s).matches();
    }

    public static void main(String[] args) {
        int numSets = Integer.parseInt(args[0]);
        int numReps = Integer.parseInt(args[1]);
        boolean b = false;

        for (int i = 0; i < numSets; i++) {
            long start = System.nanoTime();
            for (int j = 0; j < numReps; j++) {
                b ^= isRomanNumeralFast("MCMLXXVI");  // Change Slow to Fast to see performance difference
            }
            long end = System.nanoTime();
            System.out.println(((end - start) / (1_000. * numReps)) + " μs.");
        }

        // Prevents VM from optimizing away everything.
        if (!b)
            System.out.println();
    }
}
package effectivejava.chapter2.item6;

import java.util.Comparator;

// Hideously slow program! Can you spot the object creation? (Page 24)
public class Sum {
    private static long sum() {
        Long sum = 0L;
        for (long i = 0; i <= Integer.MAX_VALUE; i++)
            sum += i;
        return sum;
    }

    public static void main(String[] args) {
        int numSets = Integer.parseInt(args[0]);
        long x = 0;

        for (int i = 0; i < numSets; i++) {
            long start = System.nanoTime();
            x += sum();
            long end = System.nanoTime();
            System.out.println((end - start) / 1_000_000. + " ms.");
        }

        // Prevents VM from optimizing away everything.
        if (x == 42)
            System.out.println();
    }
}

 

 条目7:

package effectivejava.chapter2.item7;
import java.util.*;

// Can you spot the "memory leak"?  (Pages 26-27)
public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        return elements[--size];
    }

    /**
     * Ensure space for at least one more element, roughly
     * doubling the capacity each time the array needs to grow.
     */
    private void ensureCapacity() {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }

//    // Corrected version of pop method (Page 27)
//    public Object pop() {
//        if (size == 0)
//            throw new EmptyStackException();
//        Object result = elements[--size];
//        elements[size] = null; // Eliminate obsolete reference
//        return result;
//    }

    public static void main(String[] args) {
        Stack stack = new Stack();
        for (String arg : args)
            stack.push(arg);

        while (true)
            System.err.println(stack.pop());
    }
}
package effectivejava.chapter2.item7;

// (Thrown by Stack program on Page 26)
public class EmptyStackException extends IllegalStateException {
}

 

package effectivejava.chapter2.item8;

import java.lang.ref.Cleaner;

// An autocloseable class using a cleaner as a safety net (Page 32)
public class Room implements AutoCloseable {
    private static final Cleaner cleaner = Cleaner.create();

    // Resource that requires cleaning. Must not refer to Room!
    private static class State implements Runnable {
        int numJunkPiles; // Number of junk piles in this room

        State(int numJunkPiles) {
            this.numJunkPiles = numJunkPiles;
        }

        // Invoked by close method or cleaner
        @Override public void run() {
            System.out.println("Cleaning room");
            numJunkPiles = 0;
        }
    }

    // The state of this room, shared with our cleanable
    private final State state;

    // Our cleanable. Cleans the room when it’s eligible for gc
    private final Cleaner.Cleanable cleanable;

    public Room(int numJunkPiles) {
        state = new State(numJunkPiles);
        cleanable = cleaner.register(this, state);
    }

    @Override public void close() {
        cleanable.clean();
    }
}
package effectivejava.chapter2.item8;

// Well-behaved client of resource with cleaner safety-net (Page 33)
public class Adult {
    public static void main(String[] args) {
        try (Room myRoom = new Room(7)) {
            System.out.println("Goodbye");
        }
    }
}
package effectivejava.chapter2.item8;

import java.util.concurrent.TimeUnit;

// Ill-behaved client of resource with cleaner safety-net (Page 33)
public class Teenager {
    public static void main(String[] args) {
        new Room(99);
        System.out.println("Peace out");

        // Uncomment next line and retest behavior, but note that you MUST NOT depend on this behavior!
//      System.gc();
    }
}
    /**
     * Registers an object and a cleaning action to run when the object
     * becomes phantom reachable.
     * Refer to the <a href="#compatible-cleaners">API Note</a> above for
     * cautions about the behavior of cleaning actions.
     *
     * @param obj   the object to monitor
     * @param action a {@code Runnable} to invoke when the object becomes phantom reachable
     * @return a {@code Cleanable} instance
     */
    public Cleanable register(Object obj, Runnable action) {
        Objects.requireNonNull(obj, "obj");
        Objects.requireNonNull(action, "action");
        return new CleanerImpl.PhantomCleanableRef(obj, this, action);
    }
import java.lang.ref.Cleaner;

 

@Override public void close() {
cleanable.clean();
}

 代码略

原文地址:https://www.cnblogs.com/cx2016/p/13262124.html