Tips
书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code
注意,书中的有些代码里方法是基于Java 9 API中的,因此JDK 最好下载 JDK 9以上的版本。java
看到相似这样的方法并不罕见:git
// Returns null to indicate an empty collection. Don't do this! private final List<Cheese> cheesesInStock = ...; /** * @return a list containing all of the cheeses in the shop, * or null if no cheeses are available for purchase. */ public List<Cheese> getCheeses() { return cheesesInStock.isEmpty() ? null : new ArrayList<>(cheesesInStock); }
没有理由对没有奶酪(Cheese)可供购买的状况进行特殊处理。这样须要在客户端作额外的代码处理可能为null的返回值,例如:程序员
List<Cheese> cheeses = shop.getCheeses(); if (cheeses != null && cheeses.contains(Cheese.STILTON)) System.out.println("Jolly good, just the thing.");
在几乎每次使用返回null来代替空集合或数组的方法时,都须要使用这种迂回的方式。 它容易出错,由于编写客户端的程序员可能忘记编写特殊状况代码来处理null返回。 多年来这种错误可能会被忽视,由于这种方法一般会返回一个或多个对象。 此外,返回null代替空容器会使返回容器的方法的实现变得复杂。github
有时有人认为,null返回值比空集合或数组更可取,由于它避免了分配空容器的开销。这个论点有两点是不成立的。首先,除非测量结果代表所讨论的分配是性能问题的真正缘由,不然不宜担忧此级别的性能(条目67)。第二,能够在不分配空集合和数组的状况下返回它们。下面是返回可能为空的集合的典型代码。一般,这就是你所须要的:数组
//The right way to return a possibly empty collection public List<Cheese> getCheeses() { return new ArrayList<>(cheesesInStock); }
若是有证据代表分配空集合会损害性能,能够经过重复返回相同的不可变空集合来避免分配,由于不可变对象能够自由共享(条目17)。下面的代码就是这样作的,使用了Collections.emptyList
方法。若是你要返回一个Set,可使用Collections.emptySet
;若是要返回Map,则使用Collections.emptyMap
。可是请记住,这是一个优化,不多须要它。若是你认为你须要它,测量一下先后的性能表现,确保它确实有帮助:性能
// Optimization - avoids allocating empty collections public List<Cheese> getCheeses() { return cheesesInStock.isEmpty() ? Collections.emptyList() : new ArrayList<>(cheesesInStock); }
数组的状况与集合的状况相同。 永远不要返回null,而是返回长度为零的数组。 一般,应该只返回一个正确长度的数组,这个长度可能为零。 请注意,咱们将一个长度为零的数组传递给toArray
方法,以指示所需的返回类型,即Cheese []
:优化
//The right way to return a possibly empty array public Cheese[] getCheeses() { return cheesesInStock.toArray(new Cheese[0]); }
若是你认为分配零长度数组会损害性能,则能够重复返回相同的零长度数组,由于全部零长度数组都是不可变的:this
// Optimization - avoids allocating empty arrays private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0]; public Cheese[] getCheeses() { return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY); }
在优化的版本中,咱们将相同的空数组传递到每一个toArray
调用中,当cheesesInStock
为空时,这个数组将从getCheeses
返回。不要为了提升性能而预先分配传递给toArray
的数组。研究代表,这样作会拔苗助长[Shipilev16]:code
// Don’t do this - preallocating the array harms performance! return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);
总之,永远不要返回null来代替空数组或集合。它使你的API更难以使用,更容易出错,而且没有性能优点。orm