Java语言和标准库功能强大,但功能强大, 责任重大 。 一方面看到很多用户代码滥用或滥用稀有的Java功能,另一方面却完全忘记了大多数基本功能之后,我决定撰写此摘要。 这不是每个Java开发人员都应该探索,了解和使用的要求和领域的列表。 相反! 我将Java功能分为三类: 日常 , 偶尔和从不(仅框架和库) 。 规则很简单:如果您发现自己经常使用给定功能,然后建议使用该功能,则可能是工程过度或试图构建过于笼统且可重复使用的功能。 如果您没有足够频繁地使用给定功能(根据我的主观清单),则可能会错过一些真正有趣且重要的机会。
请注意,我只关注Java,JVM和JDK。 我不建议您使用哪些框架以及使用的可能性。 我还假设了典型的服务器端面向业务的应用程序。
日复一日
假定每天都要使用Java语言的以下功能。 如果您从未见过它们,或者很少使用它们,则可以仔细看看,它们确实很有帮助:
- 类,接口,包 –认真。 将您的代码放在类中。 您还记得大学时曾说过,类是封装的数据+对数据起作用的方法吗? 仅具有状态的类几乎不是一个结构。 仅包含方法的类只是一个包含函数的名称空间。 必要时也请使用接口。 但是在创建仅具有一个实现的接口之前,请三思而后行。 也许您不需要中间人? 但是,请遵循完善的命名约定将所有内容打包放入软件包中。
- 静态方法 –不要害怕它们。 但是,仅将它们用于无状态实用程序方法。 永远不要在
static
方法中编码任何业务逻辑。 -
ExecutorService
–线程池 –必须创建并有效使用线程池,了解排队和Future<T>
工作方式。 不要重新实现线程池,每当有人说生产者-消费者时都要考虑一下它们。 -
Atomic
-*系列 –不要使用synchronized
来勉强读取/更新某些计数器或原子引用。Atomic
*系列类使用有效的比较和交换低级指令来达到惊人的效率。 确保您了解这些类提供的保证。 - 设计模式 –从技术上讲不是Java语言的一部分,而是必不可少的。 您应该,知道,了解和使用它们,但要谨慎而谨慎。 就像使用界面一样-不要太过分。 GoF甚至EI模式通常应出现在代码库中。 但是,让模式出现在您的思维过程中,而不是让思维过程受模式驱动。
- 内置集合(包括并发集合) –您绝对必须了解并使用内置集合,并了解
List
,Map
和Set
之间的区别。 使用线程安全的集合对您来说不是问题。 了解性能特征并对其背后的实现进行基本概述。 这真的很基本。 还知道并使用各种BlockingQueue
实现。 并发很困难,不要自己重新实现其中的一些东西就更难了。 - 内置的注释 -注释是在这里留下来,学会使用
@Override
(和@Deprecated
在一定程度上)每天一致。 - 异常 –使用未经检查的异常来表示异常,异常失败,需要采取措施。 了解如何处理受检查的异常。 学习阅读堆栈跟踪。
- 尝试使用资源 –熟悉这种神话般的语言构造。 如果您的班级需要任何清理,请实施
AutoCloseable
。 - 阻止IO –使用
Reader
/Writer
,InputStream
/OutputStream
类是您应该真正熟悉的东西。 理解它们之间的区别,不用担心就使用缓冲和其他装饰器。
这将结束您应使用的日常工具的列表。 如果您从未听说过或仅偶尔使用过它们,请仔细研究它们,因为它们可能会成为您的救星。
偶尔
以下是您不应该害怕使用的语言功能,但也不应滥用它们。 如果您发现自己每天都在利用它们,或者在午餐前几次看到这些功能,那么您的设计可能有问题。 我从后端企业Java开发人员的角度来看。 这些类型的功能很有用,但不太常用。
- 继承和抽象类 –实际上,事实证明,我不经常使用继承,而且我也不是很想念它。 由接口驱动的多态性要灵活得多,尤其是在Java中缺乏特性的情况下。 比起继承,也更喜欢组合 。 太多级别的继承会导致代码难以维护。
- 正则表达式 – 有些人遇到问题时会认为“我知道,我会使用正则表达式”。 现在他们有两个问题。 。 没有正则表达式的世界将更加无聊和麻烦。 它们对于解析常规语言(而不是HTML )非常有用,但是它太容易过度使用了。 如果您发现自己整天都在正则表达式之前进行制作,测试,修复和维护,则可能是在使用错误的工具来完成这项工作。 我一直以来最喜欢的:
public static boolean isNegative(int x) {return Integer.toString(x).matches('-[0-9]+'); }
-
Semaphore
,CountDownLatch
,CyclicBarrier
等 –与infomouswait()
/notify()
对相比,它们在一个数量级上都非常有用。 但是即使滥用它们,也不会阻止您出现并发错误。 当您经常看到这些同步机制时,请考虑线程安全的集合或某些框架。 - 用户代码中的泛型类型 –使用内置集合和具有泛型类型的其他类不仅应该是日常实践,而且对您来说应该显而易见。 但是我的意思是自己开发代码,以获取或返回通用类型。 像这样:
public <T, F> ContractValidator<T extends Contract> T validate(Validator<T>, F object)
有时有必要在您自己的代码中使用泛型,但不要太meta- 。 当然,静态类型和类型安全应该是您的首要任务,但是也许您可以避免使用太多的泛型,复杂类型?
- JVM中的脚本语言 –您知道JDK具有内置JavaScript解释器吗? 而且您几乎可以插入其他任何语言,例如Groovy或JRuby? 有时,将小脚本嵌入应用程序中更为简单,即使客户也可以更改。 这种情况并不常见,但是在瞬息万变的市场中,重新部署可能不是一种选择。 只需记住,如果脚本代码的总行数超过代码总数的1%,则应开始担心维护。
- Java NIO –很难做到正确,甚至很难从中受益。 但是在极少数情况下,您实际上必须使用NIO压缩尽可能多的性能和可伸缩性。 但是,更喜欢可以为您执行此操作的库。 同样在正常情况下,阻塞IO通常就足够了。
-
synchronized
关键字 –出于简单原因,您不应过于频繁地使用它。 它使用的次数越多,执行的频率就越高,从而影响性能。 请考虑使用线程安全的集合和原子原始包装器。 还要确保您始终了解哪个对象用作互斥体。
我认为上述功能很有价值且很重要,但不一定每天都在起作用。 如果您每天都看到其中的任何一个,则可能表示设计过度设计或……经验不足的开发人员。 经验带来简单。 但是,您可能也有非常不同的要求,这也适用于第三组。
永不(请考虑:仅框架和库开发人员)
您应该了解并理解以下功能背后的原理,以便了解框架和库。 而且您必须了解它们以有效地为我们服务,我认为如果有问题的人只是阅读所用库的代码,就可以避免有关StackOverflow的太多问题。 但是理解并不意味着使用。 您几乎永远都不要直接使用它们,它们大多是高级的,肮脏的和复杂的。 即使出现这种功能,也可能导致严重的头痛。
- 套接字 –认真地说,套接字。 您必须了解TCP / IP堆栈的工作原理,在线程方面要非常自觉,在解释数据时要小心,对流保持警惕。 远离使用纯套接字,有数百个将它们包装起来并提供更高级别抽象的库– HTTP,FTP,NTP,SMB,电子邮件…(例如,请参见Apache Commons net )。 您会惊讶于编写体面的HTTP客户端或服务器有多么困难。 而且,如果您需要为某些专有协议编写服务器,请绝对考虑使用Netty 。
- 反思 –在业务代码中没有内省类和方法的地方。 框架离不开反思,我离不开。 反射会使您的代码变慢,不安全且难看。 通常,AOP就足够了。 我什至会说传递
Class<T>
实例是一种代码味道。 - 动态代理和字节码操作 –
Proxy
类很棒,但就像反射一样,仅应由支持您的框架和库使用。 它们是轻量级AOP的基本构建块。 如果您的业务应用程序(不是框架或库,甚至Mockito都使用这些技术!)需要字节码生成或操作(例如ASM或CGLIB )–你陷入了深渊我会为你祈祷。 - 类加载器 –与类加载器有关的所有内容。 您必须了解它们,层次结构,字节码等。但是,如果您编写自己的类加载器,那将是通往地狱的道路。 并不是说它是如此复杂,但是它可能是不必要的。 留给应用服务器。
-
Object.html#clone()
–老实说,我不记得我是否在整个(Java开发人员)生命中都使用过这种方法。 我只是……没有……而且我找不到使用它的任何理由。 我要么有一个显式的复制构造函数,要么更好地使用不可变对象。 您有任何合法的用例吗? 好像是1990年代... - 本机方法 – JDK中有一些方法 ,即使对于诸如计算正弦函数之类的小任务也是如此。 但是Java不再是全班最慢的孩子,实际上恰恰相反。 另外,我无法想象使用标准库或第三方库无法实现哪种逻辑。 最后,本机方法很难正确解决,您会遇到低级的,令人讨厌的错误,尤其是在内存管理方面。
- 自定义集合 -遵循原始JavaDoc中定义的所有合同实施全新集合非常困难 。 像Hibernate这样的框架使用特殊的持久化集合。 很少需要一个针对您的需求的集合,以至于内置集合都不够好。
-
ThreadLocal
–库和框架经常使用线程局部变量。 但是出于两个不相关的原因,您永远不要尝试利用它们。 首先,ThreadLocal
通常是您想潜入的隐藏半全局参数。 这使您的代码难以推理和测试。 其次,如果未正确清理ThreadLocal
很容易引入内存泄漏(请参阅this , this , this和this和…) - WeakReference和SoftReference –这些类是相当低级的,在实现与垃圾回收良好配合的缓存时非常有用。 幸运的是,有很多开源缓存库,因此您不必自己编写。 了解这些类的作用,但不要使用它们。
-
com.sun.*
和sun.*
软件包,尤其是sun.misc.Unsafe
–远离这些软件包,只是……不要去那里。 没有理由探索这些专有的,未记录的文档,并且不能保证保留向后兼容的类。 只是假装他们不在那里。 为什么要使用Unsafe
?
当然,上面的列表是完全主观的,很可能不是确定的。 如果您认为某些物品放置在错误的位置或完全丢失了某些物品,建议您提出评论和建议。 我想构建一个摘要,可以在代码审查期间或评估项目时作为参考。
参考: Java具有 JCG合作伙伴 Tomasz Nurkiewicz在Java及社区博客上的适用性 。
翻译自: https://www.javacodegeeks.com/2012/10/java-features-applicability.html