大多数开发者想当然地认为性能优化是复杂的,需要大量的经验和知识。嗯,不能说完全错了。优化应用程序以获得最佳性能并非易事。但是,这并不意味着如果您不具备这些知识就不能做任何事情。这里有11个易于遵循的提示和最佳实践,可帮助您创建性能良好的应用程序。大多数建议都是针对Java的。但也有一些与语言无关的建议,可以应用于所有应用程序和编程语言。在讨论特定于Java的性能调优技巧之前,让我们先看看一般技巧。1.在知道有必要之前不要优化这可能是最重要的性能调优技术之一。您应该遵循常见的最佳实践并尝试有效地实施用例。但是,这并不意味着您应该替换任何标准库或构建复杂的优化,直到您证明有必要为止。在大多数情况下,过早的优化会花费大量时间并使代码难以阅读和维护。更糟糕的是,这些优化通常不会带来任何好处,因为您花费大量时间优化应用程序的非关键部分。那么,你如何证明你需要优化某些东西呢?首先,您需要定义您的应用程序代码应该有多快,例如,指定所有API调用的最大响应时间,或指定在特定时间范围内要导入的记录数。完成此操作后,您可以衡量应用程序的哪些部分运行缓慢且需要改进。然后,转到第二个技巧。2.使用剖析器找到真正的瓶颈在您遵循第一个建议并确定应用程序中需要改进的某些部分之后,您从哪里开始呢?您可以通过两种方式解决问题:·查看您的代码,从看起来可疑或您认为可能导致问题的部分开始。或者使用分析器并获取有关代码每个部分的行为和性能的详细信息。希望我不需要解释为什么您应该始终遵循第二种方法。很明显,基于分析器的方法可以让您更好地了解代码的性能影响,并让您专注于最关键的部分。如果您曾经使用过性能分析器,您就会记得您是多么惊讶地发现您的代码的哪些部分导致了一次单击的性能问题。老实说,我的第一个猜测不止一次把我引向了错误的方向。3.为整个应用程序创建性能测试套件这是另一个通用技巧,可以帮助您避免在将性能改进部署到生产后经常发生的许多意外问题。您应该始终定义一个性能测试套件来测试整个应用程序,并在性能改进前后运行它。这些额外的测试运行将帮助您识别更改对功能和性能的副作用,并确保您最终不会得到弊大于利的更新。如果您正在使用由应用程序的多个不同部分使用的组件(例如数据库或缓存),这一点尤其重要。4.首先解决最大的瓶颈在创建测试套件并使用分析器分析您的应用程序之后,您可以列出需要解决以提高性能的问题列表。这很好,但它仍然没有回答您应该从哪里开始的问题。您可以专注于速效,或从最重要的问题着手。速赢一开始可能很有吸引力,因为您可以很快显示初步结果。但有时,您可能需要说服其他团队成员或管理层相信分析是值得的——因为效果暂时是不可见的。但总的来说,我建议首先处理最重要的性能问题。这会给你最大的性能提升,你可能永远不需要解决其中的一些问题来满足你的性能需求。常见的性能调优技巧到此结束。让我们仔细看看一些特定于Java的技巧。5.使用StringBuilder以编程方式连接字符串在Java中连接字符串有许多不同的选项。例如,您可以使用简单的+或+=,以及StringBuffer或StringBuilder。那么,您应该选择哪种方法呢?答案取决于连接字符串的代码。如果您以编程方式向String添加新内容,例如在for循环中,那么您应该使用StringBuilder。它易于使用并提供比StringBuffer更好的性能。但请记住,与StringBuffer相比,StringBuilder不是线程安全的,可能并不适合所有用例。您只需要实例化一个新的StringBuilder并调用append方法将新的部分添加到String中。添加所有部分后,您可以调用toString()方法来检索串联的字符串。下面的代码片段显示了一个简单的示例。在每次迭代期间,此循环将i转换为String并将其与一个空格一起添加到StringBuildersb中。所以,最后,这段代码会在日志文件中写入“Thisisatest0123456789”。StringBuildersb=newStringBuilder("Thisisatest");for(inti=0;i<10;i++){sb.append(i);sb.append("");}logo.info(sb.toString());正如您在代码片段中看到的,您可以将String的第一个元素提供给构造函数。这将创建一个新的StringBuilder,其中包含提供的字符串和16个额外字符的容量。当你向StringBuilder添加更多字符时,JVM会动态增加StringBuilder的大小。如果您已经知道String将包含多少个字符,则可以将该数字提供给各种构造函数方法,以实例化具有已定义容量的StringBuilder。这进一步提高了效率,因为它不需要动态扩展其容量。6.在语句中使用+连接字符串当您用Java实现第一个应用程序时,可能有人告诉您不应该使用+连接字符串。如果您在应用程序逻辑中连接字符串,则为真。字符串是不可变的,每个字符串的拼接结果存储在一个新的String对象中。这需要额外的内存,并且会减慢您的应用程序,尤其是当您在一个循环中连接多个字符串时。在这些情况下,您应该遵循技巧5并使用StringBuilder。但如果您只是将字符串分成多行以提高代码的可读性,则情况并非如此。Queryq=em.createQuery("SELECTa.id,a.firstName,a.lastName"+"FROMAuthora"+"WHEREa.id=:id");在这些情况下,您应该使用简单的+来连接您的字符串。Java编译器对此进行了优化,并在编译时执行连接。因此,在运行时,您的代码将只使用1个字符串,不需要连接。7.尽可能使用基元另一种避免任何开销并提高应用程序性能的简单快捷的方法是使用基元类型而不是它们的包装类。因此,最好用int代替Integer,用double代替Double。这允许JVM将值存储在堆栈而不是堆上,以减少内存消耗并提高处理效率。8.尽量避免使用BigInteger和BigDecimal既然我们正在讨论数据类型,那么让我们也快速了解一下BigInteger和BigDecimal。后者尤其因其精确性而广受欢迎。但这是有代价的。BigInteger和BigDecimal比简单的long或double需要更多的内存,并且会显着降低所有计算速度。所以,如果你需要额外的精度,或者数字会超出long的范围,那么你最好三思而后行。这可能是解决性能问题唯一需要更改的地方,尤其是在实现数学算法时。9.先检查当前的日志级别这个建议应该是显而易见的,但不幸的是,很多程序员在写代码的时候大多忽略了它。在创建调试消息之前,您应该始终先检查当前日志级别。否则,您可能会创建一个稍后将被忽略的日志消息字符串。这里有两个反面例子。//不要做thislog.debug(“User[”+userName+“]用[”+i+“]”调用方法X);//或thislog.debug(String.format(“User[%s]用[%d]",userName,i))调用了方法X);在上述两种情况下,您将执行所有必要的步骤来创建日志消息,而不知道日志消息是否会被日志框架使用。因此,在创建调试消息之前检查当前日志级别是个好主意。//执行此操作10.使用ApacheCommonsStringUtils.Replace而不是String.replace通常,String.replace方法工作正常并且非常高效,尤其是在使用Java9时。但是,如果您的应用程序需要大量替换操作并且没有更新到最新的Java版本,仍然需要找到更快、更高效的替代方案。另一个答案是ApacheCommonsLang的StringUtils.replace方法。正如LukasEder在他最近的一篇博文中所描述的那样,StringUtils.replace方法远远优于Java8的String.replace方法。而且它只需要很小的改动。即在应用pom.xml中添加ApacheCommonsLang项目的Maven依赖,将String.replace方法的调用全部替换为StringUtils.replace方法。//将thistest.replace("test","simpletest");//替换为thisStringUtils.replace(test,"test","simpletest");11.缓存昂贵的资源,例如数据库连接缓存以避免重复执行昂贵或常用代码片段的流行解决方案。总体思路很简单:重用这些资源比重复创建新资源成本更低。一个典型的例子是在池中缓存数据库连接。创建新连接需要时间,如果您重用现有连接,则可以避免这种情况。您还可以找到Java语言本身的其他示例。例如,Integer类的valueOf方法缓存介于-128和127之间的值。您可能会争辩说创建一个新的Integer并不太昂贵,但由于它经常被使用,所以缓存最常用的值也可以提供性能优势。但是,当您考虑缓存时,请记住缓存实现也有开销。您需要花费额外的内存来存储可重用的资源,因此您可能需要管理缓存以使资源可访问,并删除过时的资源。因此,在开始缓存任何资源之前,请确保实施缓存是值得的,也就是说,它们必须被充分使用。总结如您所见,有时不需要做太多工作就可以提高应用程序的性能。本文中的大部分建议只需要您稍作努力即可将它们应用到您的代码中。但最重要的是与语言无关的:在你知道有必要之前不要优化,使用分析器找到真正的瓶颈,首先处理最大的瓶颈如果这篇文章对你有帮助,别忘了给我一个3莲,点赞,转发,评论,下次见!获取方式:点赞、评论、关闭~学习更多JAVA知识技能,关注并私信博主(666)
