Jackson如何反序列化Java14中的record类型?

Java14近日发布,其中引入了新的record类型,虽然这是个预览特性,但是也不妨碍我们尝试下。

record类型

record类型和普通的类相比,有几个特点

  1. 每个字段都是private final的,类本身是final的
  2. 类只有一个所有传递所有参数的构造函数
  3. 每个字段会自动会有一个get方法,但是名字和字段名一致(没有get前缀)
  4. 可以给字段添加注解,支持FIELD、METHOD和PARAMETER(如果一个注解是FIELD、METHOD和PARAMETER的,那么注解会在字段、get方法和构造函数参数上同时出现)
Read the rest

Java 14中的 JEP 358: Helpful NullPointerExceptions是如何实现的

Java 14在2020年3月17号正式发布,不久AdoptOpenJDK也跟进发布了新版。

JEP 358: Helpful NullPointerExceptions

其中对使用者比较有用的功能是 JEP 358: Helpful NullPointerExceptions,即在NullPointerException的message中指明为什么产生了这个NPE。

示例代码如下(需要Java14,并配置参数-XX:+ShowCodeDetailsInExceptionMessages):

public class Main
Read the rest

jdk 8u91一个lambda类型推断的bug

公司内部发布maven包是在公司构建服务器上编译的。最近一次上线,发现同样的代码,在本地的jdk8上能编译通过,但是在构建服务器上,就编译报错。

简化后的代码如下:

// JavaBugTest.java
import java.util.Optional;

public class JavaBugTest {

    public static <T, E extends ThrowableT execute(RetryCallback<T, EretryCallback) throws E {
        return retryCallback.doWithRetry(new
Read the rest

HashMap的初始容量设置

TL;DR

知道大小的情况下,new HashMap的时候这么写:

HashMap<Integer, Stringmap = Maps.newHashMapWithExpectedSize(expectedSize);

正文

Java中的HashMap大家都很熟悉,其底层使用了Node数组来存储Map中的数据。但是如果存储的数据太多,空间不够,就需要扩容这个数组来存储新的数据了。

这个具体可以看下java.util.HashMap#resize函数,基本上就是将数组中的内容逐个复制到新数组中。

扩容操作时间复杂度O(n),空间复杂度O(n),还需要计算对象的hash。在平常编码中,如果我们提前知道map的大小,就应该指定初始容量,避免发生扩容。… Read the rest

如何以string方式查看heapdump中的byte数组

昨天,线上OOM,dump下来hprof文件,里面有两个大数组:

从表象上来看,和thrift导致的oom是一样的:

但是问题是,这种情况是怎么出现的呢?

找了好几种办法,没有头绪。

最后发现,把这个byte数组转成string就看到了thrift服务端的错误信息。

当时为了快速解决问题,是直接将前60个byte手抄到java代码中,然后转成string输出。

但是,不能一直都这么干,所以就看了下如何方便的将heapdump中的byte[]输出为string。

查了半天,发现OQL没有这样的功能,但是VisualVM倒是可以间接的做这事:… Read the rest

不正确使用Thrift Client导致的OOM问题排查

最近线上有一个多线程的任务,会调用几个Thrift服务。 上线后观察到这个脚本在执行一段时间后,会有好几次Full GC,然后就会报OOM错误。

那就先下载heap dump(推荐压缩后,使用rz下载到本地),使用VisualVM分析。首先切换到Objects页面,看下是否有大对象:

heapdump-Objects

可以看到,有两个byte数组占用了大量内存,也可以看到这个对象是在Java栈上的,接下来就是要找谁在使用这个变量。

右击该对象,点击Select in Threads:

可以看到是名为rebuilder-9的线程,再查看这个线程的调用栈:… Read the rest

lambda表达式导致arthas无法redefine的问题

作为一个从PHP转Java的人,发现alibaba的arthas很好用。通过arthas的redefine命令,可以像PHP一样,不用重新发布,就可以改变程序行为。

但是用多了,发现很多时候,我们就改了几行代码,甚至有的时候就添加了一行日志,就无法redefine了。提示

redefine error! java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method

它提示我们新增加方法,那我们就看看是不是新增加了方法。通过javap来查看定义的方法:… Read the rest

LeetCode 1190. Reverse Substrings Between Each Pair of Parentheses

题意

每层括号里面的东西需要反转一次。即在在偶数层括号里面的字符是正序的,在奇数层括号里面的字符是逆序的。然后拼成结果。

例子:

"(abcd)"
反转之后就是:
cdba
"(u(love)i)"
love不反转,u,love,i三个反转,答案为:
iloveu

思路

网上有人直接用栈存储,每一个元素代表当前层级括号中的字符串,如果遇到括号关闭,将当前层级字符串反转再append到上一级的字符串中。

但是,括号层级一多,字符串反转的次数就非常多了。而且很多反转都是没有必要的。

其实直接递归就好,或者说分治:

每个括号内部都算作独立的子问题,如果正序,直接逐个append,逆序则反向append;如果遇到括号,则继续分治。… Read the rest

从fastjson漏洞谈防御式编程

最近,fastjson又爆出一个漏洞,在解析特殊字符的时候,直接OOM:

首先分析一下整体流程:

在scanString时,会直接读取两个字符:

而在next方法中,每次读取都会将bp的值加一(即使没有从输入中读取字符):

public final char next() {
    int index = ++bp;
    return ch = (index = this.len ? //
            EOI //
            : text.charAt(index));
}

在处理完\x之后,继续解析剩下的字符。由于没有更多字符了,所以读到的总是EOI,然后进入如下分支:

if (ch
Read the rest

LeetCode双周赛-第七场

总是抽不出时间参加LeetCode周日上午的周赛,最近发现有周六晚上10点半的双周赛,就参加了两把。这次是第七场

第一题:Single-Row Keyboard

题意

一个只有一行的键盘,随机有26个字母,给定单词,先移动到对应的单词,然后输入第一个字母,再移动,再输入第二个字母,以此类推。问输入这个单词需要移动多长。

题解

题目难度easy,直接模拟就好:

public class Solution {
    public int calculateTime(String keyboard, String word) {
        int res
Read the rest