问题标签 [effective-java]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
5 回答
1227 浏览

java - Java 泛型(有界通配符)

根据 Joshua Bloch 的“Effective Java”一书,有一条关于如何/何时在泛型中使用有界通配符的规则。这条规则就是 PECS(Producer-Extends,Comsumer-Super)。当我研究以下示例时:

我知道这条规则非常适合这个例子。我必须将该方法声明pushAll为以下示例:

但是,如果我有以下示例,会发生什么?

我必须声明pushAll如下:

根据PECS规则,上述声明是错误的。但我想要 a Stackof Integers 并传递给这个Stacka Number。为什么不去做呢?
为什么我应该总是使用extends关键字?为什么使用super是错误的?
当然,同样代表消费者的观点。为什么消费者应该永远是super


PS:更具体地说,您可以在参考书的“第 28 项”部分找到上述示例。

0 投票
4 回答
645 浏览

java - 一种扩展可实例化类并添加值组件同时保留 equals 合约的方法

Joshua Blotch 的Effective Java指出:

equals除非您愿意放弃面向对象抽象的好处,否则无法在保留契约的同时扩展可实例化类并添加值组件。

Effective Java给出了一些破坏对称性传递性Liskov 替换原则的示例。我想你已经阅读了该项目。我认为我不应该在这里发布整个项目。但是我找到了一个遵守合同的解决方案:

Point:_

ColorPoint:_

我知道在这种情况下应该使用组合,但我想知道我的解决方案是否真的遵守equals合同。如果是的话,Effective Java声明的错误是什么

0 投票
3 回答
1494 浏览

java - 为什么我们在 Collections.max() 方法中需要有界通配符

我读过 Joshua Bloch 写的很棒的“Effective Java”。但是书中的一个例子让我不清楚。它取自关于泛型的章节,确切的项目是“第 28 条:使用有界通配符提高 API 灵活性”

在本项目中,它展示了如何使用有界类型参数和有界通配符类型编写从集合中选择最大元素的算法的最通用和防弹(从类型系统的角度来看)版本。

编写的静态方法的最终签名如下所示:

Collections#max它与标准库中的函数之一基本相同。

我理解为什么我们在T extends Comparable<? super T>类型约束中需要有界通配符,但是在参数的类型中真的有必要吗?在我看来,如果我们只离开List<T>or Collection<T>,那将是一样的,不是吗?我的意思是这样的:

我已经编写了以下使用两个签名的愚蠢示例,但没有看到任何差异:

那么你能举一个例子,说明这种简化的签名是不可接受的吗?

PS 以及为什么T extends Object在正式实施中?

回答

好吧,感谢@Bohemian,我设法弄清楚它们之间有什么区别。

考虑以下两种辅助方法

当然,为超类及其子类重载方法并不是很聪明,但它让我们看看实际推断出的返回值类型(和以前points一样List<ColoredPoint>)。

对于这两种方法,推断类型都是ColoredPoint.

有时您希望明确传递给重载函数的类型。您可以通过以下几种方式进行操作:

你可以投:

还是没区别...

或者你可以告诉编译器应该使用语法推断什么类型class.<type>method

啊哈!这是答案。List<ColoredPoint>不能传递给函数期待Collection<Point>,因为泛型不是协变的(不像数组),但可以传递给函数期待Collection<? extends Point>

我不确定在这种情况下在哪里或谁可能更喜欢使用显式类型参数,但至少它显示了wrongMin可能不合适的地方。

感谢@erickson 和@tom-hawtin-tackline 提供有关T extends Object约束目的的答案。

0 投票
2 回答
75 浏览

java - 过度检查与未来可扩展性权衡

我可以确定名为 returnlist() 的“我的代码”永远不会返回 null。因此,当我在增强的 for 循环中循环时,我不做任何空指针检查。但是,从维护的角度来看,这似乎不是一个好的做法,因为将来有人可能会无意中修改代码库,或者有人会覆盖这个调用,而被覆盖的函数可能不够谨慎,无法返回空集合。

因此,使问题具有通用性,该问题旨在了解在何处绘制权衡线的最佳实践。我完全理解这种情况没有明确的规则,只是寻求最佳实践。

  1. 在自己编写的代码中添加过多的检查会增加混乱,但可以确保其免受未来修改的影响。

  2. 减少检查,因为“你知道它不会返回 null”使代码干净,但我们面临意外修改的风险。

0 投票
2 回答
933 浏览

java - 通过接口引用对象。总是?

一个来自有效java的代码,这里我们使用aList来遵守通过接口引用对象的良好实践。

假设我们有一个car接口并且2wheel4wheel具体的子类。是否甚至建议(似乎相当肯定)构造一个“汽车”类型的列表?

代替

0 投票
2 回答
222 浏览

java - 如果较高级别处理异常,是否应在较低级别检查异常

这是来自 Effective java 的引用。

“在可能的情况下,处理来自较低层的异常的最佳方法是避免它们,通过确保较低级别的方法成功。有时您可以通过在将较高级别方法的参数传递给较低级别​​之前检查较高级别方法的参数的有效性来做到这一点层。”

考虑一个名为“AccessControlContext actx”的对象,它从处理程序传播到较低级别。我们可以对“actx!= null”进行更高级别的检查,但是否需要再次在较低级别进行检查?

例如在伪代码中:

尽管问题嵌套在评论中,但要反复阐述。较低级别的冗余检查可确保防御性编码,但是 - 它是冗余的。它可能在 javadocs 中清楚地说明它不接受 null,但这并不能解决拥有无错误代码的目的。我们应该重复异常检查吗?

注意:这是一个随机示例。我的问题并不特定于这个例子。这是一个更广泛的问题,旨在了解复制异常的程度。

0 投票
2 回答
66 浏览

java - 依赖对象是保存为实例变量还是只是从 getter 获得的值?

考虑一个简单的 'MyCalendar' 类的例子,它有 3 个 getter 'getDay、getMonth 和 getYear'。如果我将 'MyCalendar' 对象传递给我的另一个类,那么以下哪个选项将是一个好方法。

选项 1:在需要时通过注入对象的 getter 调用所需参数。

或者

选项 2:分配从注入对象的 getter 获得的值作为初始化的一部分。

如果答案是选择 1,那么:如果需要像在循环中那样多次访问一个字段: for (..some imaginary usecase) { mycal.getDate(); 在这种情况下,有一个本地副本有好处吗?

0 投票
3 回答
105 浏览

java - 接口是否应该用于类型参数

我读过Effective Java,它强调尽可能使用接口作为返回类型。扩展论点,我想知道以下哪种方法是首选/被认为是一种好的做法。

选项1:

选项 2:

0 投票
6 回答
5460 浏览

java - 如果我覆盖 Java 中的“equals”方法,为什么需要覆盖哈希码?

我知道只要equals在 Java 中重写该方法,就需要重写哈希码。那只是一份合同。我试图理解这背后的逻辑。我正在阅读Joshua Bloch的 *Effective Java ,我遇到了这段代码(第 9 项,第 45 页):

这是他在文中提到的,我很难理解。

此时,您可能希望m.get(new PhoneNumber(707, 867, 5309))返回“Jenny”,但它返回 null。请注意,其中涉及两个 PhoneNumber 实例:一个用于插入 HashMap,第二个相等的实例用于(尝试)检索。PhoneNumber 类未能覆盖 hashCode 导致两个相等的实例具有不相等的哈希码,这违反了哈希码协定。因此,get 方法可能会在与 put 方法存储电话号码的哈希桶不同的哈希桶中查找电话号码

我不明白他所说的两个 PhoneNumber 实例是什么。只有我在m.put(new PhoneNumber(707, 867, 5309), "Jenny"). 我也再次寻找这个对象,它应该返回相同的哈希码,即使它从对象类继承了 hashCode 方法。为什么会这样?这里的一些解释会有很大帮助。

0 投票
4 回答
301 浏览

java - 你应该避免 Guavas Ordering.usingToString() 吗?

这个问题是在阅读 Joshua Bloch 的《Effective Java》后提示的。特别是在 Item #10 中,他认为解析对象的字符串表示并将其用于除更友好的打印输出/调试之外的任何事情都是不好的做法。原因是这样的使用“容易出错,如果你改变格式会导致脆弱的系统崩溃”。在我看来,番石榴Ordering.usingToString()就是一个例子。那么使用它是不好的做法吗?