java循坏

总览

当您第一次学习开发时,您会看到关于不同功能的过分笼统的陈述,它们对于设计,性能,清晰度,可维护性都是不好的,感觉就像是黑客,或者他们只是不喜欢它。

这可能会得到现实世界经验的支持,在实际经验中,删除功能的使用可以改善代码。 有时这是因为开发人员不知道如何正确使用该功能,或者该功能固有地容易出错(取决于您是否喜欢它)

当时尚或您的团队改变并且此功能变得很好甚至是首选方法时,这令人感到不安。

在这篇文章中,我将介绍一些人们讨厌的功能,以及为什么我认为使用正确的功能应该是有益的力量。 功能并不像是/否,好/坏,就像许多人相信的那样。

检查异常

对于开发人员不喜欢考虑错误处理的程度,我经常感到惊讶。 新开发人员甚至不喜欢阅读错误消息。 这是艰苦的工作,他们抱怨应用程序崩溃,“它不起作用”。 他们不知道为什么错误消息和堆栈转储经常告诉他们如果他们只能看到线索的地方到底出了什么问题,为什么会引发异常。 当我出于跟踪目的而写出堆栈跟踪信息时,许多人只会看到日志没有错误时就像崩溃一样。 阅读错误消息是一种技巧,起初它可能会让人不知所措。

同样,也经常避免以有用的方式处理异常。 我不知道该异常该怎么办,我宁愿记录该异常并假装该异常未发生,或者只是炸掉,然后让操作人员或GUI用户处理错误的能力最弱。

结果,许多经验丰富的开发人员都讨厌检查异常。 但是,我听到的越多,我越高兴Java检查了异常,因为我坚信Java确实会发现忽略异常非常容易,并且只要不被它们烦恼就让应用程序死亡。

检查异常当然可以被过度使用。 问题应该是在引发检查异常时; 我是否想通过迫使他们对错误处理进行一点思考来惹恼开发人员调用代码? 如果答案是肯定的,则抛出一个已检查的异常。

恕我直言,这是lambda设计的失败,因为它无法透明地处理检查的异常。 例如,作为自然代码块,可以抛出未处理的异常,就像处理未经检查的异常和错误一样。 但是,考虑到lambda和函数式编程的历史,它们根本不喜欢副作用,更不用说快捷错误处理了,这也就不足为奇了。

您可以通过重新抛出已检查的异常(好像它是未检查的异常)来解决lambda的限制。 之所以可以这样做是因为JVM没有检查异常的概念,它像泛型一样是编译时检查。 我的首选方法是使用Unsafe.rethrowException,但还有3种其他方式可以做到这一点。 尽管Thread.currentThread()。stop(e)总是很安全,但它在Java 8中不再起作用。

Thread.currentThread()。stop(e)不安全吗?

当方法Thread.stop(Throwable)可能导致另一个线程在代码的随机部分触发异常时,它是不安全的。 这可能是一部分代码中未检查到的异常,也可能是抛出该异常的原因,该异常捕获在线程的某些部分,但其他部分则使您不知所措。

但是,它不安全的主要原因是,它可能会使原子操作处于不一致状态的代码锁定部分的同步状态,从而以微妙且不可测试的方式破坏内存。
更令人困惑的是,Throwable的堆栈跟踪与实际引发异常的线程的堆栈跟踪不匹配。

但是Thread.currentThread()。stop(e)呢? 这将触发当前线程在当前行上引发异常。 这并不比仅使用throw异常执行正在执行的编译器无法检查的操作更糟。 问题是编译器并不总是知道您在做什么,以及它是否真的安全。 对于仿制药,这被归类为“未经检查的演员表”,这是一个警告,您可以通过注释将其禁用。 Java不能很好地支持带有已检查异常的同类操作,您最终会使用hack,或者更糟的是将真正的已检查异常隐藏为运行时异常,这意味着调用者无法正确处理它。

使用

对我来说,这是一个新的“规则”。 我知道它来自哪里,但是该规则比应该应用的地方有更多例外。 让我们首先考虑所有可以使用重载static的上下文。

  1. 静态可变字段
  2. 静态不可变字段(指向不变的对象的最终原始或最终字段)
  3. 静态方法。
  4. 静态类(没有隐式引用外部实例)
  5. 静态初始化程序块。

我同意使用静态可变字段很可能是新手错误,还是有可能避免的事情。 如果您看到静态字段在构造函数中被更改,则几乎可以肯定是一个错误(即使没有,我也会避免),我相信这是避免所有静态语句的原因。

但是,在所有其他情况下,使用static不仅性能更高,而且更清楚。 它显示此字段对于每个实例都不同,或者该方法或类并不隐式依赖于实例。

简而言之,static是好的,可变的static字段是例外,而不是规则。

Singletons不好吗?

单例的问题来自两个方向。 它们是有效的全局可变状态,使其难以维护或封装(例如在单元测试中),并且支持自动接线。 也就是说,任何组件都可以访问它,从而使您的依赖项变得不清楚并且难以管理。 由于这些原因,一些开发人员讨厌它们。

但是,遵循良好的依赖关系注入是一种应该应用于所有组件(无论是否单例)的方法,并且应该避免通过单例避免全局可变状态。

如果排除全局状态和自连接组件,则剩下的Singleton是不可变的,并通过依赖注入传递,在这种情况下,它们可以正常工作。 我用于实现策略的一种常见模式是将枚举与一个实现接口的实例一起使用。

enum MyComparator implements Comparator {INSTANCE;public int compare(MyObject o1, MyObject o2) {// something a bit too complicated to put in a lambda}}

该实例可以通过依赖项注入作为Comparator的实现传递,并且没有可变状态,可以在线程和单元测试之间安全地使用它。

我可以让一个库或框架为我做一件非常简单的事情吗?

库和框架可以为您节省大量时间和精力,使您自己的代码执行在其他地方已经可以使用的操作。

即使您想编写自己的代码,我也强烈建议您了解现有库和框架的功能,以便从中学习。 自己编写它不是避免理解任何现有解决方案的捷径。 一位记者曾经绝望地写到一位有抱负的记者。 不喜欢读书,只喜欢写作。 在软件开发中也是如此。

但是,我已经看到(在Stackoverflow上)开发人员竭尽全力避免将自己的代码用于琐碎的示例。 他们觉得如果使用库,它必须比他们编写的任何东西都要好。 问题在于它是假定的。 添加库不会增加复杂性,您对库有很好的了解,而且您将不需要学习编写可以信任的代码。

一些开发人员使用框架来帮助学习实际上是一种方法论。 实际上,开发人员通常会使用纯Java进行依赖注入的框架,但是他们要么不信任自己,要么不信任自己的团队来这样做。

在高性能空间中,代码越简单,应用程序所做的工作就越少,使用更少的活动部件进行维护就越容易,并且运行速度也就越快。 您需要使用最少的库和框架,这些库和框架应相当容易理解,以便使系统发挥最佳性能。

用双倍赚钱不好吗?

使用小数而不考虑舍入会给您带来意想不到的结果。 从正面看,对于双精度数,通常显然是错误的,例如10.99999999999998,而不是11。

有些人认为BigDecimal是解决方案。 但是,问题在于BigDecimal具有自己的陷阱,很难进行验证/读取/写入,但是如果没有,最糟糕的情况是看起来正确。 举个例子:

double d = 1.0 / 3 * 3 + 0.01;BigDecimal bd1 = BigDecimal.valueOf(1.0).divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(3)).add(BigDecimal.valueOf(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);BigDecimal bd2 = BigDecimal.valueOf(1.0).divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(3).add(BigDecimal.valueOf(0.01))).setScale(2, BigDecimal.ROUND_HALF_UP);System.out.println("d: " + d);System.out.println("bd1: " + bd1);System.out.println("bd2: " + bd2);

这将产生三个不同的结果。 通过观察,哪一个产生正确的结果? 您能说出bd1和bd2之间的区别吗?

打印:

d: 1.01
bd1: 1.00
bd2: 0.99

您可以从输出中看到哪个错误吗? 实际上答案应该是1.01。

BigDecimal的另一个难题是equals和compareTo的行为不同。 当compareTo()返回0时,equals()可以为false。即,在BigDecimal 1.0中,等于1.00时为false,因为比例不同。

BigDecimal的问题在于,您获得的代码通常更难于理解,并且会产生看起来不正确的错误结果。 BigDecimal的速度明显较慢,并且会产生大量垃圾。 (这在Java 8的每个版本中都在改进)在某些情况下,BigDecimal是最佳解决方案,但并非如某些人所反对的那样。

如果BigDecimal不是一个很好的选择,还有其他吗? int和long通常以固定的精度使用,例如,整数而不是分数。 这有一些挑战,您必须记住小数位在哪里。 如果Java支持值类型,将它们用作金钱包装器并为您提供更多安全性可能是有意义的,但是处理整数基元的控制,说明和性能可能会有所提高。

使用

对于NullPointerException Java的开发人员而言,重复获得NullPointerException是一种消耗体力的经历。 我真的必须为Java中数组中的每个对象,每个元素创建一个新实例吗? 其他语言则不需要这样做,因为通常是通过嵌入式数据结构来完成的。 (某些正在考虑用于Java的东西)

即使是经验丰富的Java开发人员也难以处理null值,并且将这种语言的null视为一个大错误。 恕我直言,问题在于替代品通常更差。 例如不是NPE的NULL对象,但也许应该已经初始化为其他对象。 在Java 8中,Optional是一个很好的添加,它使对非结果的处理更加清晰。 我认为这对于那些与NullPointerException斗争的人很有用,因为它迫使您考虑可能根本没有结果。 这不能解决未初始化字段的问题。

我个人不喜欢它,因为它解决了一个问题,可以通过正确处理null来更广泛地解决问题,但是我知道对于许多人来说,这是一种改进。

一个常见的问题是; 我应该如何知道变量为空? 这是我心中错误的方法。 应该是,为什么要假设它不能为null? 如果您不能回答该问题,则必须假定它可以为null,并且如果不进行检查,NPE也就不会感到惊讶。

您可能会争辩说Java可以使用更多的语法糖来制作处理Elvis运算符之类的null清除程序的代码,但我认为问题在于开发人员没有充分考虑null值。 例如,您是否在打开枚举变量之前检查它是否为null? (我认为应该有一个case nullcase null :在switch中,但不存在或陷入default :但事实并非如此)

快速编写代码有多重要?

Java不是一种简洁的语言,没有IDE可以为您编写一半的代码,如果您花了一整天时间编写代码,那么编写esp将会非常痛苦。

但这就是开发人员整日不做的事情吗? 实际上,他们没有。 开发人员不会花费很多时间来编写代码,他们会花费90%(用于新代码)到99%(用于遗留代码)来理解问题

你可能会说; 我一整天以后写一千行代码,然后重新编写代码(通常使其更短),一段时间后我修复了代码。但是,尽管您仍然想起这段代码,但是如果您只是编写最后需要的代码(或从打印输出中完成),然后将其除以在项目上花费的总时间,从头到尾,您可能会发现实际上每天少于100行代码,每天可能少于10行。

所以,如果那段时间不是写最终产品,那您实际上在做什么? 据了解,最终用户需要什么,以及实施该解决方案需要什么。

曾经有人告诉我; 如果您在错误的位置钻Kong,则无论钻Kong多快,多大,有多深或有多少个Kong都无所谓。

结论

我听到了从初学者到杰出开发人员的观点,声称您不应该/我无法想象为什么/如果您使用X,您应该被解雇,应该只使用Y。我发现这样的陈述很少是100%准确的。 通常,要么存在极端情况,有时在非常常见的情况下,这种陈述具有误导性或完全不正确。

我会持怀疑态度来对待任何这样的广泛评论,而且他们常常发现一旦发现其他人没有相同的看法,他们就必须限定所说的内容。

翻译自: https://www.javacodegeeks.com/2015/05/what-are-the-bad-features-of-java.html

java循坏

java循坏_Java的坏功能是什么相关推荐

  1. java开发指南_Java 12新功能完整指南

    java开发指南 六个月飞得如此之快,是时候再次仔细研究一下即将发布的新JDK版本. 让我们满足Java 12及其向开发人员介绍的功能. 自Oracle推出加速六个月的发布节奏以来已经有一段时间了,要 ...

  2. java购物车后台_java开发——购物车功能如何实现

    java web开发_购物车功能实现 之前没有接触过购物车的东东,也不知道购物车应该怎么做,所以在查询了很多资料,总结一下购物车的功能实现. 查询的资料,找到三种方法: 1.用cookie实现购物车: ...

  3. java job定时任务_java实现job功能,定时开启任务

    在开发的过程中,有时候需要java实现job功能,定时开启或者每个一段时间重复一个任务. 本文就写一个简单的java job功能 1.首先需要job的执行内容写出来.job类需要继承java.util ...

  4. java搜索代码_Java实现搜索功能代码详解

    首先,我们要清楚搜索框中根据关键字进行条件搜索发送的是get请求,并且是向当前页面发送get请求 //示例代码 请求路径为当前页面路径 "/product" 当我们要实现多条件搜索 ...

  5. java监控任务进度_Java Swing组件实现进度监视功能示例

    本文实例讲述了java swing组件实现进度监视功能.分享给大家供大家参考,具体如下: 实例一: import java.awt.event.actionevent; import java.awt ...

  6. java使用:: 表达式_Java 13:切换表达式的增强功能

    java使用:: 表达式 您可能还记得我以前的文章,在Java 12中,传统的switch语句得到了增强,因此可以用作表达式. 在Java 13中,对该功能进行了进一步的更改 . break语句不能再 ...

  7. java lambda函数_Java SE 8新功能介绍:使用Lambda Expression进行函数式编程

    java lambda函数 " Java SE 8新功能浏览 "系列的这篇文章将深入了解Lambda表达式 . 我将向您展示Lambda表达式的几种不同用法. 它们都具有功能接口的 ...

  8. java 基础包的功能_Java 8的功能基础

    java 基础包的功能 Java 8彻底改变了Java. 它很可能是过去10年中最重要的Java版本. 有很多新功能,包括默认方法,方法和构造函数引用以及lambda, 仅举几例 . 更有趣的功能之一 ...

  9. java ping 实现的_java实现ping功能

    一.纯Java实现ICMP的ping命令 import java.io.*; import java.net.*; import java.nio.channels.*; import java.ut ...

最新文章

  1. 笔记本蓝牙显示输入码无效_如何凭借一把键盘游走桌面?米物蓝牙双模键盘
  2. ICRA2021 SLAM方向论文汇总
  3. 解决sublime 乱码显示GBK编码文件
  4. 论文研读:Automatic Temporal Segment Detection and Affect Recognition From Face and Body Display
  5. problem k: 查找某一个数_quot;细节魔鬼quot; 二分查找
  6. Java生鲜电商平台-订单中心服务架构与异常订单逻辑
  7. 启动/关闭数据库、实例及服务
  8. 问答 请问使用OK(raw:jpg)能返回多张图片吗
  9. pycharm的terminal无法识别到命令 pytest 不是内部或外部命令,也不是可运行的程序 或批处理文件。
  10. (day 39 - 动态规划) 剑指 Offer 47. 礼物的最大价值
  11. yum在linux安装mysql数据库_linux安装mysql(yum安装,比较简单)
  12. php和java环境整合
  13. 市面上好用的 Markdown 编辑器,我给你整理好了
  14. 【安安教具】-【工具】-【随机点名】模拟器 教你如何用python制作随机点名器
  15. Windows密码设置及破解
  16. 大数据开发比赛echarts所有要学习的主要图表 简单化 得分点
  17. 2022持续学习-架构相关
  18. 非阻塞IO处理上几个常见问题
  19. 关于延长程序员清明节假期的通知!
  20. 在线视频编辑 剪辑系统源码 支持AE所有特效

热门文章

  1. POJ1151-Atlantis【线段树,扫描线,离散化】
  2. 2018CCPC吉林赛区(重现赛)补题部分——F线段树待补
  3. 【Splay】文艺平衡树(金牌导航 Splay-2)
  4. 告诉你,Spring Boot 真是个牛逼货
  5. jstack(查看线程)、jmap(查看内存)和jstat(性能分析)命令
  6. Java 调用EXE
  7. 参加双车项目的一些感触
  8. mysql添加新用户
  9. 第三章选择结构(一)
  10. SpringCloud Netflix Eureka