java 最佳实践_Java API编码的10个最佳实践

让我与您分享编码Java时的10个微妙的最佳实践:

9883862f56f9b8c0941d8f83463debd0.png

1.记住C ++析构函数

还记得C ++析构函数吗?没有?然后,您可能会很幸运,因为您无需再调试任何代码,而不会由于删除对象后未释放分配的内存而导致内存泄漏。感谢Sun / Oracle实现垃圾回收!

但是,尽管如此,破坏者还是有一个有趣的特征。通常以相反的顺序释放内存是有意义的。在使用类似析构函数的语义进行操作时,也要在Java中记住这一点:

· 当使用@Before和@After JUnit批注时

· 分配时,释放JDBC资源

· 调用超级方法时

还有其他各种用例。这是一个具体示例,显示了如何实现某些事件侦听器SPI:

9125b1fe27af974209a071db2eacc44c.png

2.不要相信您早期的SPI发展判断

向消费者提供SPI是使他们能够将自定义行为注入您的库/代码中的简便方法。但是请注意,您的SPI演变判断可能会欺骗您,使您认为您(不需要)该附加参数。确实,不应及早添加任何功能。但是一旦发布了SPI,并决定遵循语义版本控制,当您意识到在某些情况下可能还需要另一个参数时,您会后悔为SPI添加了一个愚蠢的单参数方法:

8441931e2745fb524489cfd2a4731e4a.png

如果您还需要消息ID和消息源怎么办?API的发展将阻止您轻松地将该参数添加到上述类型。使用Java 8,您可以添加防御者方法来“捍卫”您糟糕的早期设计决策:

985f118edc075cb5d943ebfecf9b1bf6.png

请注意,不幸的是,防御者方法不能设为final。

但是,比使用数十种方法污染SPI更好的方法是,仅为此目的使用上下文对象(或参数对象)。

0abbba0e2a86ee3aa6af40b954dea116.png

与EventListener SPI相比,您可以更轻松地开发MessageContext API,因为实施该应用程序的用户将更少。

规则

:无论何时指定SPI,都应考虑使用上下文/参数对象,而不是编写带有固定数量参数的方法。

备注:通常也可以通过专用的MessageResult类型(可以通过构建器API构造)来传递结果,这是一个好主意。这将为您的SPI增加更多的SPI演进灵活性。

3.避免返回匿名,本地或内部类

Swing程序员可能有几个键盘快捷键可以为其数百个匿名类生成代码。在许多情况下,创建它们很不错,因为您可以本地遵守接口,而无需经历思考完整SPI子类型生命周期的“麻烦”。

但是,您不应该过于频繁地使用匿名类,局部类或内部类,原因很简单:它们保留对外部实例的引用。并且,如果您不小心,它们会将外部实例拖到任何地方,例如,拖到本地类之外的某个范围。这可能是内存泄漏的主要来源,因为整个对象图会突然以微妙的方式纠缠在一起。

规则

:每当编写匿名,本地或内部类时,请检查是否可以使其成为静态类,甚至是常规顶级类。避免将匿名,本地或内部类实例从方法返回到外部作用域。

备注:对于简单对象实例化,围绕双花括号有一些聪明的做法:

e420362be0d56296ea62e8a7395de5d5.png

这利用了JLS§8.6中指定的 Java实例初始化程序。看起来不错(也许有点奇怪),但确实是个坏主意。否则,将成为完全独立的HashMap实例现在将保留对外部实例的引用,无论碰巧是什么。此外,您将创建其他类供类加载器管理。

4.立即开始编写SAM!

Java 8正在敲门。随Java 8一起提供lambda,无论您是否喜欢。不过,您的API使用者可能会喜欢它们,因此您最好确保他们可以尽可能多地使用它们。因此,除非你的API接受简单的“标量”类型,如int,long,String,Date,让你的API接受地对空导弹尽可能多地。

什么是SAM?SAM是单一抽象方法[Type]。也称为功能接口,很快将使用@FunctionalInterface注释进行注释。这与规则2配合得很好,其中EventListener实际上是SAM。最好的SAM是具有单个参数的SAM,因为它们将进一步简化lambda的编写。想象写作

ff2f77daf1ee167a9c509e4f5a4e4923.png

代替

c6deac70139b65b6a47d5bbf14e170ef.png

想象一下通过jOOX进行的 XML处理,它具有几个SAM:

476efc90fb75d86de276cb48089ec14f.png

规则:与您的API使用者友好,现在已经编写SAM /功能接口。

5.避免从API方法返回null

我曾经写过一两次关于Java的NULL的博客。我还写了关于Java 8的Optional简介的博客。从学术和实践的角度来看,这些都是有趣的话题。

虽然NULL和NullPointerExceptions在Java中可能会持续困扰一段时间,但您仍可以通过设计API来避免用户遇到任何问题。尽可能避免从API方法返回null。您的API使用者应能够在适用的情况下链接方法:

405487ec4690e29f3911cee0ef428deb.png

在以上代码段中,所有方法均不应返回null。实际上,使用null的语义(缺少值)通常应该是非常例外的。在诸如jQuery(或jOOX,其Java端口)之类的库中,由于始终在可迭代对象上进行操作,因此完全避免了null 。是否匹配某项与下一个方法调用无关。

由于延迟初始化,通常还会出现空值。在许多情况下,也可以避免延迟初始化,而不会对性能产生任何重大影响。实际上,仅应谨慎使用惰性初始化。如果涉及大型数据结构。

规则

:尽可能避免从方法返回null。仅对“未初始化”或“缺少”的语义使用null。

6.切勿从API方法返回空数组或列表

虽然在某些情况下从方法返回null可以,但是绝对没有用过返回null数组或null集合的用例!让我们考虑一下可怕的java.io.File.list()方法。它返回:

在此抽象路径名表示的目录中命名文件和目录的字符串数组。如果目录为空,则数组为空。如果此抽象路径名不表示目录,或者发生I / O错误,则返回null。

因此,处理此方法的正确方法是

b35cc0c0b6afc10ef2cb5dcc9c055de2.png

空检查真的必要吗?大多数I / O操作都会产生IOException,但是此操作返回null。Null无法保存任何指示为什么发生I / O错误的错误消息。因此,这在三种方式上是错误的:

· 空无助于发现错误

· Null不允许将I / O错误与不是目录的File实例区分开

· 每个人都会忘记空值

在集合上下文中,“空缺”的概念最好通过空数组或集合来实现。除了再一次进行延迟初始化外,几乎没有有用的数组或集合。

规则

:数组或集合绝不能为空。

7.避免状态,发挥作用

HTTP的优点在于它是无状态的。所有相关状态都在每个请求和每个响应中传递。这对于REST的命名至关重要:代表性状态转移。当用Java完成时,这也很棒。当方法接收有状态参数对象时,可以根据规则2来考虑它。如果状态在此类对象中传递,而不是从外部操纵,则事情会变得更加简单。以JDBC为例。以下示例从存储过程中获取游标:

90d98315b9a43276bd6454e4c6d765e9.png

这些使JDBC成为难以处理的API。每个对象都是难以置信的有状态且难以操纵。具体来说,有两个主要问题:

· 在多线程环境中正确处理有状态的API非常困难

· 很难使有状态资源在全球范围内可用,因为没有记录状态

082465afac88142cc7ae40d27cc67634.png

编写这样的方法给Java生态系统带来一点JavaScript的感觉。当然,您可能希望将实际类型限制为在实际情况下更受限的类型,例如String...。而且由于您不想限制太多,您可能会认为用通用T代替Object是一个好主意:

bbea93b96db24195a44caa86ed97e35f.png

但事实并非如此。T总是可以推断为Object。实际上,您最好不要将泛型与上述方法一起使用。更重要的是,您可能认为可以重载上述方法,但不能:

0967ff384432822314f3fd6f395cfe6d.png

看起来您可以选择将String消息传递给该方法。但是这里的电话怎么办?

0c89362ce72dc9cfd12bda8bd7320839.png

编译器将推断 extends Serializable & Comparable>>for T,这使调用变得模棱两可!

因此,每当您拥有一个“所有人都接受”的签名(即使它是通用的)时,您将再也无法安全地重载它。API使用者可能只是幸运地“偶然地”选择了编译器选择“正确的”最具体的方法。但是,它们也可能被欺骗使用“全部接受”方法,或者它们可能根本无法调用任何方法。

规则

:如果可以,请避免“全部接受”签名。如果不能,则不要重载这种方法。

结论

Java是野兽。与其他更高级的语言不同,它已经发展到今天。那可能是一件好事,因为在Java的发展速度下,已经有数百项警告,这些警告只能通过多年的经验来掌握。

最后,开发这么多年我也总结了一套学习Java的资料与面试题,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。

fe0b0d0c6486a15753348e7d59856419.png

c76c5e1ac7cf7ad7f8107e9131262214.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值