Loading...
守株阁Java中的条件编译 Back to Home

Java中的条件编译

Created2022-01-12|Updated2026-01-24
|Word Count:7|Reading Time:1mins|Post Views:

Java中的条件编译

Author: magicliang
Link: https://magicliang.github.io/2022/01/12/Java%E4%B8%AD%E7%9A%84%E6%9D%A1%E4%BB%B6%E7%BC%96%E8%AF%91/
Copyright Notice: All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.
Java
Related Articles
cover
2017-10-23
昂贵的异常
抛出问题 Joshua Bloch 在《Effective Java》的 Item 57 里明确地提到过,不要试图用 Exception 的跳转来代替正常的程序控制流。他列举了很多原因,但特别提到了抛出异常会使得整个程序运行变慢。抛出异常远比普通的 return、break 等操作对控制流、数据流的性能影响要大,它就只适合拿来作异常分支的控制语句,而不能拿来编写正常的逻辑。 Throwing exception is expensive. 这句话在 Java 的程序员世界里面已经成为老生常谈,却很少有人谈及到底抛出异常比正常的程序跳转返回慢在哪里,有多慢。"不要滥用异常"好像一个猴子定律,人们知道不能这么做,却不明白为什么不能这么做。 此前读了一位同事写的好文《Java虚拟机是如何处理异常的》,深入地分析了 JVM 对异常跳转的处理过程:JVM 会通过异常表的机制,优化异常抛出和正常返回之间的性能差异。仅从程序计数器的移动上来讲,抛出一个异常对栈帧的弹栈并不比直接返回更昂贵。写在前头的结论是:"try-catch 语句块几乎不会影响程序运行性能!...
cover
2017-11-30
Java中的幽灵类型
什么是幽灵类型 先上结论:幽灵类型(Phantom Type)顾名思义,就是幽灵般的类型,这种类型往往在运行时可以消失,因为在运行时没有任何作用,它们最大的特点就是没有任何实例(Java 的 Void 就是一个不可实例化类型的例子,常被用作幽灵类型的类型参数,如 Future<Void>)。幽灵类型是一种可以把有些运行时才能检测到的错误,在编译时检测出来的技巧。按照有些老外的观点,就是"Making Wrong Code Look Wrong"。在面向对象的编程语言之中,幽灵类型的实现,往往与状态模式较为接近,但比状态模式提供了更强的纠错功能。在 Java 5 以后的版本里,程序员可以使用泛型。通过泛型的类型参数,Java 中也拥有了幽灵类型的能力。 上面的阐述是不是很难看懂?直接进入具体的例子。假设有一个飞机控制程序,操作飞机起飞或者落地。这个程序有一个非常强的业务约束,就是必须保证飞机一开始必须出现在地上,只有在地上的飞机可以起飞,只有起飞的飞机可以落地,那么应该怎样设计程序(主要是类型关系),来保证这个约束必然成立呢? 定义状态接口 先来定义...
cover
2018-05-29
JPA 的 id 生成策略
JPA 有一个@GeneratedValue注解,有一个strategy attribute,如 @GeneratedValue(strategy = GenerationType.IDENTITY)。 常见的可选策略主要有IDENTITY和SEQUENCE。 GenerationType.IDENTITY 要求底层有一个 integer 或者 bigint 类型的自增列( auto-incremented column)。自增列的赋值必须在插入操作之后发生,因为这个原因,Hibernate 无法进行各种优化(特别是 JDBC 的 batch 处理,一次 flush 操作会产生很多条insert 语句,分别执行)。如果事务回滚,自增列的值就会被丢弃。数据库在这个自增操作上有个高度优化的轻量级锁机制,性能非常棒。 MySQL 支持这种 id 生成策略, 使用 MySQL 应该尽量使用这个策略,即使它无法优化。 JPA 用它生成 id,会一条一条地插入新的 entity。 GenerationType.SEQUENCE 数据库有一个所谓的 sequence 对象,可以通过 selec...
cover
2018-06-19
如何做性能测试的问题下的答案
试着回答一下这个问题。 首先要划分系统类型:有状态还是无状态,业务系统还是存储系统。根据不同的业务场景,设立性能测试的目标:是要测 QPS,还是 TPS 还是 TPS,还是任何其他【性能】-从广义来讲,一个存储系统到底能够以多高的平均时延来管理大多的存储空间,可能也是性能的一种。 有了性能测试的目标,接下来就是拆解用例。如果把性能测试归为测试的话,测试就需要测试用例,测试用例只是用例的形式化表达。把用户的使用场景勾勒出来,把每一步拆解成的流程图或者时序图–我们已经得到了一个纸上的集成测试计划,只是没有跟性能挂上钩。 接下来就进入真正写测试用例的环节了。 我们的测试报告如果要涵盖足够立体的信息,则既要了解每一个环节/接口/API 的性能指标,又要了解整体的性能指标。 这个时候测试工具的覆盖面就很重要了。如果我们选择偏黑盒的测试工具,apache ab /JMeter,则我们的测试用例就要围绕着对外交互的 API写,也只能测到外围接口的性能。这样的测试用例写起来最简单,无需侵入任何内部代码中。 如果我们使用了 JMH 一类的工具,则可以自由编写对任何方法的测试用例。但需要对系统有非常...
cover
2018-09-07
日期与时间
JSR 310 Java Date与Time API 新旧 API 的更迭 旧的 Java API 主要包括java.util.Date和java.util.Calendar 两个包的内容。这两个包的时间类型是可变的。如 Date 的实例可以通过 setYear 来产生变化。 JSR 310 中包括的日期类型主要有: 计算机时间:Instant,对应 java.util.Date,它代表了一个确定的时间点,即相对于标准Java纪元(1970年1月1日)的偏移量;但与java.util.Date类不同的是其精确到了纳秒级别。 人类时间:对应于人类自身的观念,比如LocalDate和LocalTime。他们代表了一般的时区概念,要么是日期(不包含时间),要么是时间(不包含日期),类似于java.sql的表示方式。此外,还有一个MonthDay,它可以存储某人的生日(不包含年份)。每个类都在内部存储正确的数据而不是像java.util.Date那样利用午夜12点来区分日期,利用1970-01-01来表示时间。这些类型的实例是 immutable 的,而且只能通过工厂方法创建。 时区...
cover
2018-10-13
卡表和 RSet
上下文 卡表和 RSet(Remember Set),是 JVM 为了解决分代收集时,live set 扫描需要穿梭到不同的代的时候的效率问题。 使用缓存表来提高查询效率,是化顺序查找为部分随机查找的一种常用的设计思路。 例如,在传统的计算机体系结构中,当我们把内存分成页以后,会有一个页表,页表又会有一个快表,作为一个中间缓存项,来帮助我们查找我们需要使用的页表项(table entry)。 JVM 在进行垃圾收集的时候,有一项非常重要的工作就是确定这一次垃圾收集的对象到底有多少个,即确定 live set 的范围。 对于新生代垃圾收集器而言,这个问题又有其特殊之处。根据 JVM 的弱分代收集假设(weak generational hypothesis)的存在,每次垃圾收集的时候,新生代的扫描范围可能很大,但新生代的 live set 不应该太大。card table/Remember Set 的设计目的,就是尽量减少无用的垃圾扫描范围,使用类似操作系统或者数据库的脏页表的形式,来做类似快表的查询。 卡表(card table) 卡表是 CMS 的解决方案。 卡表通常在 JV...
avatar
magicliang
关于技术以及人生
Articles
344
Tags
223
Categories
6
Github
Announcement
人生只是,守株待兔
Recent Posts
JVM 的内存模型与线程
JVM 的内存模型与线程2026-02-07
Maven 完全指南
Maven 完全指南2026-02-07
Docker 完全指南
Docker 完全指南2026-02-07
Guava 解析
Guava 解析2026-02-07
一致性哈希与数据分片
一致性哈希与数据分片2026-02-07
© 2017 - 2026 By magicliangFramework Hexo 8.1.1|Theme Butterfly 5.5.2