- 写 Java 代码至今,在应对可能冲突的共享资源操作时会尽量用 JDK 1.5 开始引入的并发锁(如 Lock 的各类实现类, ReentrantLock 等) 进行锁定,而不是原来的
synchronized关键字强硬低性能锁。
这里是应用 JDK 1.5 的Lock的基本操作步骤private Lock lock = new ReentrantLock(); private void operate() {
如此,
// 安全操作 ....
lock.lock();
try {
// 对共享资源的操作 ...
} finally {
lock.unlock();
}
}operate()就是一个线程安全的方法,任何对它的调用都安排到了一个队列里等着。但有时候上锁需要考虑更细的粒度,下面是一个演示案例,引出第一个问题
Read More JSON 表示布尔值标准的形式是
true和false,如果 Java 对应的类型是对象 Boolean,那么在 JSON 中也可以是null。如果收到 JSON 数据是用 'Y'/'N', 或 'Yes'/'No' 来表示布尔值的,那么使用 Java 的 Jackson 库如何把它们反序列化为相应的布尔属性值呢?如果按照 JSON 规范必须把内容中的布尔值全部转换为
true或false, 然而再反序列化,否则需要定制Boolean类型的反序列化类,可应用到全局的 boolean 类型,或指派给特定的 boolean 类型属性。如果尝试反序列化
Y, 或N为 Java 的 boolean 值,会有只接受 true 或 false 的异常:com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.lang.Boolean from String "Y": only "true" or "false" recognized
具体步骤是: Read More
如果一个 Java 类在初始化时会有外部依赖,这就给单元测试创建它的实例时造成困难。当然被测试类可以改造为依赖全部构造时注入或创建实例后延迟注入,这里不考虑这种改造。
可以参看我以前一篇类似的日志:使用 JMockit 来 mock 构造函数
来说下面的例子1public class OrderService { 2 private PriceInquiry priceInquiry = new PriceInquiry(); 3 ......... 4 5 public double totalPrice() { 6 return priceInquiry.retrieve(....); 7 } 8}
假如上面的代码是不能改动的,并且在new PriceInquiry()时依赖于网络环境,所以单机情况不能创建成功。也就使得测试时试图new OrderService();
会失败。并且试图用 Mockito 的@InjectMocks也不行 Read More
本文准确来讲是探讨如何用 Jackson 来序列化 Apache avro 对象,因为简单用 Jackson 来序列化 Apache avro 对象会报错。原因是序列化Schema getSchema()时会报错,后面会讲到,需要序列化时忽略该属性。那么能不能在getSchema()上加上@JsonIgnore来忽略该属性呢?原理上是通的。不过手工修改的 avsc 生成的 Java 文件随时会因为重新编译而还原,所以不太具有实际可操作性,当然通过定制编译 avsc 用的模板文件来加入@JsonIgnore是另一回事。
由于不能在要忽略的字段上添加JsonIgnore来控制,而如果我们明确了要忽略的字段类型的话,是能够定制 Jackson 的 ObjectMapper 来屏蔽某个特定的类型。来看下面序列化 Apache avro 对象的例子:
假设我们有一个 Apache 的 Schema 文件user.avsc, 内容如下: Read More最初看到 Java 9 的这个新特性没太在意,及至重新关注到 Spring 5/Springboot 2 的响应式编程的时候才真正重视起 Reactive Streams(响应式流或反应式流)。应用响应式流的编程也就叫做响应式编程(Reactive Programming),无论是翻译成反应式编程都有些令人摸不准头脑。与此对应的在 Web 设计方面有一个叫做响应式 Web 设计(Responsive web design),两个词都译作响应式,却有些差别,大概是 Reactive 被译为反应的原因之一。
通过这里对 Reactive Streams 的学习,主要目的是为了进一步掌握 Spring 5/Springboot 2 的响应式 MVC 作铺垫的,不至于猛然间见 Flux, Mono 而不知所措。
函数式响应式编程概念最早来自于九十年代末,这也激发了微软的 Erik Meijer 设计开发了 .NET 的 Rx(Reactive eXtension) 库,以及到后来 Netflix 的 RxJava 也与他有关系。Reactive Stream 更像是一种编程模式,致力于解决一个生产者产生一系列消息,一个或多个去消费它们的问题。两者的名词我们会用: producer-consumer(生产者-消费者), source/sink(水源/水槽, Akka Stream 用了这个概念), publisher-subscriber(发布者-订阅者)。
既然 Reactive Stream 和 Java 8 引入的 Stream 都叫做流,它们之间有什么关系呢?有一点关系,Java 8 的 Stream 主要关注在流的过滤,映射,合并,而 Reactive Stream 更进一层,侧重的是流的产生与消费,即流在生产与消费者之间的协调。 Read More

Java 六个月的版本迭代周期让我们突然间有些喘不过气来,又 Java 11 才会是一个长期支持版本,如果可能的话我们将会是从 Java 8 直接往 Java 11 跳去。在 Java 8 大行其道,裹足不前的当下,谈论着未来 Java 11 不确定的新特性,有一种看着别人家碗里的不过瘾,还要看着别人家锅里的感觉。
本篇原本只是为了对 Java 11 潜在的原始字符串字面量(Raw String Literals)的哨探,同时考虑到 Java 10 仅有的一个语言层面的新特性
var局部变量类型推断,所以顺带介绍一下。我这儿把它称之为 var 局部变量类型推断,说明了
var类型推断并不适用于类或实例的变量,或方法的参数。而且var也并未上升为一个 Java 的关键字,我们仍然可以用var作为变量或方法名。对局部变量用
var进行类型推断的代码示例变化如下:1List<String> list = new ArrayList<>(); //Java 10 以前 2var list = new ArrayList<String>(); //Java 10 开始 3 4int age = 100; //Java 10 以前 5var age = 100; //Java 10 开始,推断为 int 类型 6 7var stream = blocks.stream(); //都不需要引入 java.util.Stream 类var学了Scala的语法,再重复一遍,var只能用于局部变量,这有一个好处就是局部变量的跨越性较小,不至于var声明的变量阅读时只有编译器知道它的确切类型。var类型推断给代码书写上的变化就是对局部变量的任何类型声明都可以替代为var。 Read More
平台之所以谓之平台,以其能建立一个生态,并与之外围达成共赢。霸道点的平台也会反噬外围生态,像微软集成浏览器,媒体播放器。还有即将的 iOS 12 要把应用商店多是收费的 AR 皮尺放到它自己系统中来,走别人的路,让别人无路可走。从此众泰皮尺部的唯一的生产工具就会是人手一部能安装 iOS 12 iPhone 了。
JDK 也不例外,Java 8 之前日期库的话 Joda-Time 是首要之选,Java 8 集成后应该是鲜有人问津。以往说到集合操作库,有两个选择,其一为 Apache Commons Collections,二为 Google 的 Guava,当然前者与后者竞争中也早已败下阵来,况且前者还受到 Java 8 的夹击。 而本文要说的可以说是 Java 9 把 Guava 中创建不可变集合的方式据为已用了,直截了当的说,凡是 Java 9 后有创建不可变集合的需求,只要用三大接口
List,Set,Map中的of(...)方法就对了。Java 9 之前,当我们需要集合相关的操作,两个选择:
Read More
什么是线程栈
继续纠缠 Java 9 的新特性,仍然是一个边角料,即 Java 9 增加了对线程栈遍历的 API。那么什么是线程栈,JVM 在创建每一个线程的同时都会创建一个私有的虚拟机栈,每一桢代表着一个方法调用,每次方法的调用与退出意味着压栈与出栈。每一桢上有局部变量,操作数常量引用等信息,这也是为什么局部变量是能最快被销毁的对象。过深的栈(比如过多的递归调用) 会出现我们程序员赖以生存的 StackOverflow。
浅显些说,线程栈就是通常我们捕获到异常后,用e.printStackTrace()看到自 main 方法追溯到当前方法的调用。例如:java.lang.RuntimeException: stack
调用层次是 main() 调用 m1(), m1() 调用 m2(), m2() 中的代码如下
at cc.unmi.TestStackWalking.m2(TestStackWalking.java:15)
at cc.unmi.TestStackWalking.m1(TestStackWalking.java:10)
at cc.unmi.TestStackWalking.main(TestStackWalking.java:6)1try { 2 throw new RuntimeException("stack"); 3} catch (Exception ex) { 4 ex.printStackTrace(); 5}
上面输出的每一行就是一个栈桢,输出了当前类名,方法名,代码行号。 Read More
我们知道 Java 的合法命名是以字母或下划线开头的字符串,当然,以前单个下划线
_也是一个合法的变量命名。但是自 Java 8 的第一个版本开始,单个下划线的变量名编译时会有警告int _ = 99;
用 Java 8 编译时提示警告:
Test.java:2: warning: '_' used as an identifier
int _ = 99;
^
(use of '_' as an identifier might not be supported in releases after Java SE 8)
1 warning这正是为 Java 9 作的预谋,以一个 LTS 版的 Java 8 作为过渡。因此,来到了 Java 9 后,单个下划线不再担当普通变量名的角色,变成了一个保留关键字,只说是另有任用。
先来看下 Java 9 中的单个下划线变量名编译时的错误提示
Test.java:2: error: as of release 9, '_' is a keyword, and may not be used as an identifier
int _ = 99;
^
1 error到底单下划线会作为什么用途呢? 已发布的 Java 10 没有给出答案,正在演进中的 Java 11 也没有相关的信息。 Read More
关于 Java 9 的新特性从某本书的最后一个说起:平台日志 API。个人没感觉这个有什么实质的用途,所谓的平台日志是指 JDK 自身代码,或者是 JVM 组件中的日志输出,而在自己应用程序代码中却不会去用这个平台日志 API。这个所谓的 Platform Logging API 名称的意义也就是在这里,平台用的,在诊断时用来观察 JDK 类或 JVM 中的日志输出,比如应该可以截获到 JVM 本地代码实现中的日志输出。对我们在项目中如何处理日志并不会有什么影响,该怎么还是怎么,不过了解多一点东西应该不会浪费脑容量的。
新加的平台日志体现在java.lang.System中新加的几个方法和类
我们可以尝试着在代码使用一下它1System.Logger logger = System.getLogger(TestLogging.class.getName()); 2logger.log(System.Logger.Level.INFO, "Hello Java 9 Platform Logging API");
输出如下May 26, 2018 10:56:51 AM cc.unmi.TestLogging main
Read More
INFO: Hello Java 9 Platform Logging API