测试
如果没有测试过,它就是不能工作的。
Java语言是一种静态类语言, 程序员经常觉得,代码能通过编译器就是没问题, 其实这只是表面上的满足编译器的语法规则而已, 迈向代码校验的第一步就是创建测试
单元测试
“单元”是指它是测试的一小部分,通常每个类都有测试来检查它所有的方法, “系统”测试则是不同的,它检查的是整个程序是否满足要求
JUnit
@BeforeAll 这个注释是在任意测试方法之前执行, 被修饰的方法必须是静态的
@AfterAll 这个注释是在所有测试方法执行结束之后执行, 被修饰的方法也必须是静态的
@BeforeEach 这个注解通常是用来注释创建或初始化公共对象的方法, 在每次测试执行之前进行, 它跟构造器有几分相似, 唯一的区别就是所有测试的所有对象都是同时创建的(而不是在测试之前创建对象), 而@BeforeEach 能保证他在测试方法执行之前调用
@AfterEach 这个是标识测试之后执行, 用于清除资源之类的
@Test 这个注释是用来让Junit来发现测试方法的
前置条件
断言(Assertions)
Java 断言语法
断言需要在运行时启动, 正常为关闭状态, 可以通过 -ea(enableAssert) 来启动程序, 也可以用 setDefaultAssertionStatus(true)来开启断言
日志
java自带的日志包不好用, 一般我们用SLF4J, SLF4J的输出格式,信息,甚至是输出的是否正常都是取决于SLF4J链接的后端包
日志等级
SLF4J提供了多个等级的日志消息, 下面的例子是”严重性”从低到高
// validating/SLF4JLevels.java
import org.slf4j.*;
public class SLF4JLevels {
private static Logger log =
LoggerFactory.getLogger(SLF4JLevels.class);
public static void main(String[] args) {
log.trace("Hello");
log.debug("Logging");
log.info("Using");
log.warn("the SLF4J");
log.error("Facade");
}
}
/* Output:
2017-05-09T06:07:52.846
[main] TRACE SLF4JLevels - Hello
2017-05-09T06:07:52.849
[main] DEBUG SLF4JLevels - Logging
2017-05-09T06:07:52.849
[main] INFO SLF4JLevels - Using
2017-05-09T06:07:52.850
[main] WARN SLF4JLevels - the SLF4J
2017-05-09T06:07:52.851
[main] ERROR SLF4JLevels - Facade
*/
你可以按照等级来查找消息, 级别通常是单独配置在XML文件中的, 如果你没有配置, 那么SLF4J将采取默认配置
调试
尽管System.out 或者日志能带来系统运行的有效见解, 但是对于困难的难题来说 , 它就是比较笨拙的,而且比较耗时
使用 JDB 调试
java调试器(JDB)是jdk内置的命令行工具,
肯定还是idea的debug好用
基准测试
基准测试意味着对代码或算法片段进行计时看哪个跑得更快,与下一节的分析和优化截然相反,分析优化是观察整个程序,找到程序中最耗时的部分。
微基准测试
写一个计时工具来比较不同的代码——>没什么用
代码的运行速度受很多影响, 如内存什么的, 如果你的数据很大, 内存满了,也会导致运行停止, 同时java虚拟机的Hotshot也非常影响运行效率, 第一次运行的”冷处理”,比”预热处理”慢等等
JMH 的引入
截止目前为止,唯一能产生像样结果的 Java 微基准测试系统就是 Java Microbenchmarking Harness
你可以在命令行编写 JMH 代码并运行它,但是推荐的方式是让 JMH 系统为你运行测试;build.gradle 文件已经配置成只需要一条命令就能运行 JMH 测试。
这里涉及到算法啥, 先不深入了解了
剖析和优化
有的时候你需要知道程序的时间花在哪了, 从而针对花费时间的代码进行调整, 解剖器可以找到这些导致程序变慢的地方, 因而你可以找到最轻松, 最明显的方式来加快程序运行
解剖器收集的信息能显示程序哪一部分消耗内存, 哪一部分最消耗内存, 甚至可以关闭垃圾回收,从而帮助限定内存分配的模式
解剖器还可以帮助检查程序中的死锁, 注意剖析跟基准测试的区别, 剖析关注的是已经运行在真实数据上的整个程序, 而基准测试关注的是程序中隔离的片段,通常是去优化算法
安装java开发工具包(JDK)时,会顺带安装一个虚拟的解剖器, 叫做VisualVM, 它会被自动安装在javac的相同目录下.
你的执行路径应该包含该目录, 启动VirsualVM的控制台指令是: >jvisualvm, 运行后会弹出一个窗口, 其中包括一些指向信息的链接
优化准则
- 避免牺牲代码的可读性
- 不要独立的看待代码的性能, 要衡量其带来的收益和你付出的工作量
- 程序大小很重要, 性能对大型的长时间运行的程序才有价值, 而不是小型程序的关注点
- 运行起来程序比一心钻研它的性能更具优先级, 一旦你的程序可以运行, 你可以通过解剖器来提高它的效率, 只有当性能是关键性因素的时候, 才需要你在开发/设计阶段考虑它
- 不要靠猜, 让解剖器来告诉你运行的平静在哪
- 不论何时, 如果可能的话 ,在不使用对象的时候设置其为 null, 这对垃圾处理系统是一个暗示
- static final 修饰的变量会被jvm优化从而提高其运行效率,因此常量经常应该使用static final修饰