java循坏_Java的坏功能是什么

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循坏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/337938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 内存 开发 经验_有一到五年开发经验的JAVA程序员需要掌握的知识与技能!...

JAVA是一种平台,也是一种程序设计语言,如何学好程序设计不仅仅适用于JAVA,对C等其他程序设计语言也一样管用。有编程高手认为,JAVA也好C也好没什么分别,拿来就用。为什么他们能达到如此境界?我想是因为编程…

C语言fgets()函数:以字符串形式读取文件

点击上方蓝字关注我&#xff0c;了解更多咨询C语言 fgets() 函数从文本文件中读取一个字符串&#xff0c;并将其保存到内存变量中。fgets() 函数位于 <stdio.h> 头文件中&#xff0c;其使用格式如下&#xff1a;fgets(字符串指针,字符个数n,文件指针);格式说明&#xff1…

js文件 import java类_实现JS脚本导入JAVA类包

本例演示怎样通过JS脚本导入JAVA类包&#xff0c;我们创建JS引擎后&#xff0c;通过eval方法调用 getScript() ,JS脚本中importPackage(java.util)为导入包。package ajava.code.javase;import javax.script.ScriptEngineManager;import javax.script.ScriptEngine;import java…

摆脱冷气_摆脱匿名类

摆脱冷气我真的很喜欢编写和阅读lambda表达式-它们简洁&#xff0c;富于表现力和时尚&#xff08;来吧&#xff0c;这样就没关系了&#xff01;&#xff09;。 将此与匿名类进行比较。 这就是为什么我喜欢摆脱它们&#xff01; 在过去的几个月里&#xff0c;这种认识慢慢地实现…

深入了解C语言

点击上方蓝字关注我&#xff0c;了解更多咨询c语言在编程语言中是偏底层的语言&#xff0c;像JavaScript&#xff0c;以及java。都是在c语言的基础上编译出来的。像操作系统&#xff1a;unix &#xff0c;linux &#xff0c;windows都是依靠c语言开发出来的&#xff0c;使用c语…

java imageview的使用_Android使用控件ImageView加载图片的方法

在 Android 加载图片一般使用 ImageView&#xff0c;这里简单记录一下这个控件的使用方法。最简单就是在 xml 里直接使用 ImageView 标签&#xff1a;android:orientation"vertical"android:layout_width"fill_parent"android:layout_height"fill_par…

jaxb报错_JAXB做错了; 尝试Xembly

jaxb报错JAXB是一项具有10年历史的Java技术&#xff0c;它使我们能够将Java对象转换为XML文档&#xff08;编组&#xff09;和返回&#xff08;取消编组&#xff09;。 我认为这项技术基于setter和getter&#xff0c;并且通过将对象转换为被动数据结构而违反了面向对象编程的关…

C语言函数注意点有哪些?

点击上方蓝字关注我&#xff0c;了解更多咨询构成C程序的基本单位是函数 C语言程序是由函数构成的&#xff0c;不存在过程。函数名代表该函数的入口地址C语言函数可以嵌套调用&#xff0c;例如&#xff1a;fun(fun(x)) &#xff1b;于C语言中&#xff0c;子程序的…

java int转byte_Java将int转换为byte时的奇怪行为?

在Java中&#xff0c;a int是32位。A byte是8 bits。最原始的类型Java中的签名&#xff0c;byte&#xff0c;short&#xff0c;int&#xff0c;和long被编码在二进制补码。(char类型是无符号的&#xff0c;符号的概念不适用boolean。)在此数字方案中&#xff0c;最高有效位指定…

jax-rs jax-ws_在JAX-RS中使用@Context [第1部分]

jax-rs jax-wsJAX-RS提供Context批注以在RESTful服务中注入各种资源。 一些最常用的注入组件是HTTP标头&#xff0c;HTTP URI相关信息。 这是完整列表&#xff08;无特定顺序&#xff09; HTTP标头 HTTP URI详细信息 安全上下文 资源上下文 请求 组态 应用 提供者 让我…

C语言中的逻辑值

点击上方蓝字关注我&#xff0c;了解更多咨询C语言中的逻辑值1.C语言中的逻辑值2.逻辑运算符的运算规律3.逻辑值的举例说明一&#xff0e;C语言中的逻辑值逻辑值即逻辑运算操作的结果。在C语言中&#xff0c;逻辑运算包括关系运算与逻辑运算。关系运算包括大于(>),小于(<…

java page size_java ducument.pagesize.a2打印时用a4可以吗

展开全部概述Document是itext的基础&#xff0c;你可以添加文档数据(用户阅读62616964757a686964616fe58685e5aeb931333339666161的信息)和元数据(pdf内部使用的信息)。在创建document对象时&#xff0c;你可以定义page size&#xff0c;page color and page margins。构造函数…

冷热复位_冷热rx-java可观察

冷热复位我自己对“热和冷可观测”的理解还很不稳定&#xff0c;但这是我到目前为止所了解的&#xff01; 冷观测 考虑一个返回rx-java Observable的API&#xff1a; import obs.Util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rx.Observable; impo…

C/C++语言重要语法之输入输出

点击上方蓝字关注我&#xff0c;了解更多咨询C语言是一种编译式的、通用的、大小写敏感的编程语言&#xff0c;完全支持面向对象开发。基本的输入输出cin和cout在C语言中&#xff0c;标准的键盘输入和屏幕输出功能分别使用scanf()和printf()两个函数实现。在C语言中&#xff0c…

mysql int number_Oracle/MySQL decimal/int/number 转字符串

有时客户需要流水数据&#xff0c;当导出为excel的时候&#xff0c;客户编号等很长数字的栏位&#xff0c;被excel变成科学记数法&#xff0c;无法正常查看。因此&#xff0c;需要将Oracle/MySQL中的decimal/int 转 varchar&#xff0c;这样在excel中就可以放心查看了。Oracle的…

C语言的“递归函数”这么难理解,为什么不丢弃它呢?

点击上方蓝字关注我&#xff0c;了解更多咨询变量就是在程序运行期间其值可以变化的量。每个变量都属于一种类型&#xff0c;每种类型都定义了变量的格式和行为。因此&#xff0c;一个变量应该有属于自己的名称&#xff0c;并且在内存中占有存储空间&#xff0c;其中&#xff0…

apache lucene_Apache Lucene的结构

apache lucene无可估量的高贵的Apache软件基金会&#xff08;Apache Software Foundation&#xff09;产生了许多巨大的产品&#xff08;Ant&#xff0c;CouchDB&#xff0c;Hadoop&#xff0c;JMeter&#xff0c;Maven&#xff0c;OpenOffice&#xff0c;Subversion等&#xf…

mysql 排序 过滤_【MYSQL】-3 排序与过滤

上周加入数据蛙二期培训&#xff0c;结束了孤独战斗的现状。断断续续自学了3个月(当然看了各种视频和各种书&#xff0c;一把辛酸泪。。。)&#xff0c;现在选择报班&#xff0c;主要还是觉得一个靠谱的组织和团队&#xff0c;可以极大缓解我学习过程中不时闪现的焦虑和无助&am…

构造函数 构造代码块_构造函数必须没有代码

构造函数 构造代码块构造函数中应完成多少工作&#xff1f; 在构造函数内部进行一些计算然后封装结果似乎是合理的。 这样&#xff0c;当对象方法需要结果时&#xff0c;我们将准备好它们。 听起来是个好方法&#xff1f; 不&#xff0c;这不对。 这是一个坏主意&#xff0c;原…

C语言按位逻辑运算符总结-与、或、非、异或

点击上方蓝字关注我&#xff0c;了解更多咨询C中有按位逻辑运算符&#xff1a;按位取反、按位与、按位或、按位异或。这4个运算符可以用于整型&#xff0c;包括char类型。按位操作针对每一个位进行操作&#xff0c;不影响左右两边的位。4个运算符的作用总结如下&#xff1a;一、…