0%

用人话解释我用过的 Class 类中的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 食用方法:classA.isAssignableFrom(classB)
* 表达的意思:classB 是不是 classA 的子类/接口 或 本身
*/
public native boolean isAssignableFrom(Class<?> cls);

// Samples, all tests passed.
import org.testng.Assert;
import org.testng.annotations.Test;

public class TestIsAssignableFrom {
@Test
public void test_isAssignableFrom (){
// 对自己使用,返回 true
Assert.assertTrue(ClassA.class.isAssignableFrom(ClassA.class));
// 父类对子类使用,返回 true
Assert.assertTrue(ClassA.class.isAssignableFrom(ClassB.class));
// 子类对父类使用,返回 false
Assert.assertFalse(ClassB.class.isAssignableFrom(ClassA.class));
// 父接口对自接口使用,返回 true
Assert.assertTrue(InterfaceC.class.isAssignableFrom(InterfaceD.class));
// 子接口对父接口使用,返回 false
Assert.assertFalse(InterfaceD.class.isAssignableFrom(InterfaceC.class));
// 接口对实现了自己的类使用,返回 true
Assert.assertTrue(InterfaceC.class.isAssignableFrom(ClassB.class));
}
}

class ClassA {}

class ClassB extends ClassA implements InterfaceC {}

interface InterfaceC {}

interface InterfaceD extends InterfaceC {}

写 UT 的时候遇到一个 NoClassDefFoundError, 以前没碰到过,记一笔

Root Cause

编译时能找到 class 但是运行时对应的类找不到了,听上去可能不点矛盾

与 ClassNotFoundException 的区别

ClassNotFoundException 的场景更多的是我们给出 class name, 然后 JVM 根据名字去 load 的时候找不到就会跑抛出这个异常

NoClassDefFoundError 则是在编译期,JVM 是能找到对应的类的,但是等运行期时找不到了

怎么修复

  1. 检测 Classpath 是不是缺少你需要的 jar 包,缺少就加一下。我本地就是这个问题,测试的 dependency 中没有类的引用,挂了
  2. 检查 error exception stack, 看看是不是类初始化时 static 部分出错了

打印 Classpath 调试

通过打印 classpath 输出当前运行环境是否缺少需要的 jar 包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.net.URL;
import java.net.URLClassLoader;

public class PrintClassPath {
public static void main(String[] args) {
ClassLoader cl = ClassLoader.getSystemClassLoader();

URL[] urls = ((URLClassLoader)cl).getURLs();

for(URL url: urls){
System.out.println(url.getFile());
}
}
}

// Output:
// /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/charsets.jar
// /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/deploy.jar
// /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/jre/lib/ext/cldrdata.jar
// ...

Refer

很全面的一个 NoClassDefFoundError 异常分析博文

简单记录一下 java 中 Date 类的使用

通过 Date 创建

默认构造函数会创建当前时间点的 Date 对象, 另外还可以通过 Date(long milliseconds) 的构造器创建指定时间的日期对象

主要方法:

  • getTime() - return milliseconds
  • before(Date) - if date is before target date
  • after(Date)
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
Date date = new Date();
// The default date fromat is: "EEE MMM dd HH:mm:ss zzz yyyy";
System.out.println(date);
System.out.println(date.getTime());
}

// Output:
// Fri Jan 03 17:47:16 CST 2020
// 1578045256817

通过 SimpleDateFormat 创建

相比于上一种方式,这种更易懂一点,而且可以指定输出格式呦(´▽`)

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) throws ParseException {
Date simpleDate = new SimpleDateFormat("yyyy-MM-dd").parse("2020-01-03");

System.out.println(simpleDate);
System.out.println(new SimpleDateFormat("MM-dd-yyyy").format(simpleDate));
}

// Output:
// Fri Jan 03 00:00:00 CST 2020
// 01-03-2020

Idea 中关于 Maven 的一些配置

Configurations

避免 import *

默认设置下,同一个包下 import 数量超过 5 个就会用 * 来代替,可以去 Setting -> editor -> code style -> java, 然后右边选择 Imports tab, 修改 ‘Class count to use import *’ 的值即可

Maven 下载仓库配

  1. Shift + Ctrl + A -> 搜索 Settings.xml, Open/Create 这个文件 -> 添加仓库地址
  2. localRepository 这个变量的地址应该是对应到本地的 .m folder 下的 repository 文件夹
  3. Settings.xml 路径可以在 ‘Build, Excutations, Deployment’ 下的 maven tag 下查看

设置 Maven 自动下载包源码

  1. Build, Excutations, Deployment -> Maven -> Importing -> Automatically download: source, documentation 打勾
  2. 回到主界面,在侧边栏的 Maven 里面会出现 ‘Download source and/or documentation’ 的按钮

Win10 下 Idea/NVIDIA 快捷键冲突

  1. NVIDIA Graphic 开启的时候 Ctrl + Alt + 方向键会变成调整显示方向的设置,和 Idea 的代码跳转冲突
  2. 右键桌面 -> 图形属性 -> 选项和支持 -> 禁用快捷键

Idea 查看 JDK 源码

File -> project setting -> SDKs -> 右边有个 Sourcepath -> 导航到 JDK 文件目录下找到 src.zip 就行了

设置条件断点

添加断点之后,在断点上右键输入你想要的条件,比如: a==10

Debug 显示设置

debug 时一些值比如 byte[] 想要看具体的值时多少,可以右键 -> Evaluate Expression… 输入表达式 new String(dmBytes) 查看,也可以通过 add to watch 输入同样的表达式

复制代码段的时候,取消格式复制

cmd+shift+A 打开搜索框,输入关键字 ‘copy as rich text’, 关闭对应的开关

IDEA中显示空格

cmd+shift+A 打开搜索框,输入关键字 ‘show withspace’, 操作对应的开关

快速实现 tab <-> space 转化

  1. cmd+shift+A 打开搜索框,输入关键字 ‘convert indents’, 选择 ‘To Spaces’
  2. 或者在输入关键字的时候直接选择 ‘To Spaces’

查看类继承关系

Navigate -> Type Hierarchy 或者 Ctrl + H

关闭 Idea 自动更新提示

快捷搜索 Automatically check update for 然后将更新选项去掉

设置注释文字不顶格子

搜索 comment code 并将 Line comment at first column 和 Block comment at frist column 的选项 disable 掉

comment code

Class 生成 Enter就会提示自动创建serialVersionUID

  1. Setting->Inspections->Serialization issues->Serializable class without ’serialVersionUID’
  2. 选上以后,在你的class中:Alt+Enter就会提示自动创建serialVersionUID了。

设置终端 log size

默认终端数量有限,稍微多点就把前面的给冲掉了,可以设置 Preferences > Editor > General > Console, 勾选 Override console cycle buffer size (1024 KB),并把值调大就行

插件

  • 查看字节码:安装 jclasslib,重启。选中文件,选择导航栏上的 view -> Show byte code with jclasslib 选项即可

快捷键

功能 Mac Win
万能快捷键 CMD + Shift + A TODO
查找类 CMD+ O TODO

Spring 中 Autowired warning

Settings -> Editor -> Code Style -> Inspections -> Spring Core -> Code -> Field injection warning 选项 disable 掉

maven-assembly-plugin not found

For newer versions of IntelliJ, enable the use plugin registry option within the Maven settings as follows:

  1. Click File -> Settings.
  2. Expand Build, Execution, Deployment -> Build Tools -> Maven. Check Use plugin registry.
  3. Click OK or Apply.

For IntelliJ 14.0.1, open the preferences—not settings—to find the plugin registry option:

  1. Click File -> Preferences. Regardless of version, also invalidate the caches:
  2. Click File -> Invalidate Caches / Restart.
  3. Click Invalidate and Restart.

When IntelliJ starts again the problem should be vanquished.

默认注释格式

默认注释格式会把双斜杠放到最前面,和习惯很不搭配,可以通过 Perferences -> settings -> Editor -> Code style -> java 跳出设置界面

到 Code generic tab 下面,将 Comment Code 选项下的 Line comment at first coumn 去掉,下一级的 Add a space at comment start 选上即可

2021-04-15

升级 Idea 之后,原来的项目在 Idea 里面编译失败,但是终端却可以。由此断定项目肯定是好的。Google 了一下,可以通过 File -> Invalidate caches -> Invalidate and Restart 重启 Idea 解决问题

简单记录一下怎么破解 idea, 主要是记录下破解的文章引用,方便以后查找,引用的文章 po 主说会持续跟新的 (~ ̄▽ ̄)~

Steps

PS: 预算充足的一定要支持正版啊啊啊啊 (●’◡’●)

  1. 去官网下载最新的 Pro 版
  2. 下载 JetbrainsCrack.jar 破解包,放到 idea 安装路径的 bin 文件夹下
  3. 打开安装好的 idea,选择试用 30 天。 进入界面之后 Help -> Edit Custom VM Options, 如果提示是否创建文件,选择 Yes
  4. 拿到刚刚的 jar 文件的绝对路径,添加到末尾,比如我这里是:-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2.4\bin\JetbrainsCrack.jar
  5. 重启 idea, 再到 Help -> Register, 选择 License server 方式,idea 会自动填入 http://jetbrains-license-server,确定
  6. 在重启一波,根据提示信息可以看到破解完成

Refer

该页面用于记录实际工作中遇到的 bug,以示警戒

2022-03-01

Migration 的时候,直接按照 Ops 给的例子提了 ticket,结果 release 版本信息没改,将修改 apply 到 patch preview 上了,吓出一身冷汗。还好那哥们比较给力,当天就改回来了。更幸运的是,标题中指明了 QA 不然就上生产了,可以提桶跑路了 ( ̄◇ ̄;)

2021-05-26 Cache Issue

几年前经手的一个功能 Manage IP Restrictions, 当时还是 QA,考虑功能时还不够完善。Dev 在修改某个值时没有将对应的 cache 清掉,导致测试经常遇到不一致的情况。产品情况下修改不是很频繁,但是没这种情况,在测试的时候可把我愁坏了,干。。。

Exception Handle 遗漏

有同事打补丁时对 checked exception 和 RunTimeException 处理有遗漏导致客户使用出问题,反馈后 debug 发现,简化后场景如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 场景描述:
*
* 在处理 filterData() 时,作者只考虑到 checked exception, 没有考虑 runtime exception.
* 实际使用时,客户在某些情况下会抛出 NPE 这种 runtime exception, 导致返回 null, 显示出现错误
*/
private List<Integer> populateDatas(datas) {
try {
for (data : datas) {
try {
filterData(data);
} catch (FilterException fe) {
System.out.println("Err when filter " + data);
}
}
} catch (Exception e) {
System.out.println("Populate data failed.");
return null;
}
}

Java 中的异常分类

Throwable关系图

常见的异常种类

RunTimeException:

  • NPE
  • AuthmeticException
  • NumberFormatException
  • IndexOutOfBoundsException

CheckedException:

  • 反射相关:NoSuchMethod,FieldException
  • NoSuchFileException

Error:

  • OutOfMemmoryError
  • ZipError

一点感悟

以后处理这样的问题还是要多留心 log, 从这个点出发的话估计这个问题发现只需要一个小时就够了。这次应为有很多干扰的 exception 跑出来,没有仔细查看导致绕了好大一个圈,要不是刚好本地有一个可以重现的样本就爆炸了╭(°A°`)╮ 谨记谨记

Event 数据量撑爆了产品环境

开发完 event 相关的 feature 之后没有对测试环境进行跟踪,功能没有问题,但是产生了很多冗余数据,比如包含了很多将 field 从 null 跟新到 “” 空字串的 event。很多 data center 因为业务过重,单这个 event 每天产生 500w 数据,Kafka 就危了。。。引以为戒。

JDBC 空字串存为 NULL

通过 JDBC 存储空字串时,他会自动将它存为 NULL

记录一个 jar 升级导致的问题

在原先的 code 中,我们有个 UT 需要 xstream 的 Mapper 类,就在 UT 里面直接实现了类接口。某天, xstream 突然被人升级到 1.4.9+ 了,原来的 UT 就挂了,在这个版本里新添加了一个方法 isReferenceable 原来的 case 是没有实现的

Cache 处理的一些小技巧

在产品中发现处理 cache 的逻辑是,更新数据时删掉对应的 cache, 然后在取数据时再重新将 cache 存储起来。以前没注意,现在再看看发现挺有意思。

@NonNull 标签

Java 方法的参数列表中加入 @NonNull 并不会在写 code 的时候为你提供 NPE check, 更多的是结合其他框架, 比如 Spring 使用, 本身只起到提示作用。

Bug track 2021-04-07

今天遇到一个很诡异的问题,在 provisioning 中有一些 saveFeature 的 log 表明有时候 save 的时候会由于缺少 param 信息导致 GetSysConfig 的时候抛异常,而且频率很高。但是当我 manual 去重现这些功能时一切正常。通过查异常的上下文,发现这些有问题的 company 多是用于自动化测试的 instance。然后又仔细对比了手动正常工作时的 log 和出问题的 log 发现当异常产生时,save 的一系列动作都是在一个 transaction 中的,manual 操作是这一系列动作应该时分布在几个 transaction 中的。再结合以前的 auto 经验,这个东西大概率就是有一些 auto case 在调用了自己写的 script 操作 save feature 的时候出了问题,导致了一系列问题。这个问题如果不是对公司现有的技术手段都有所涉及,还真是不好找呢。。。

一个判断条件的优化

在 code review 的时候,有一个 if 需要判断 Boolean 对象为为空或者 false 才执行我就写了如下代码

1
2
3
if (Objects.nonNull(obj) || !obj) {
// do something
}

然后 Yi 就给了建议

1
2
3
if (ojb != Boolean.True) {
// do something
}

建议的修改更简单明了,哈哈

命令行查找目标文件夹(ls)

想要使用 ls 查找当前目录下的某个特定前缀的文件夹,但是 ls prefix* 会将对应的文件夹下面的自文件也列出来,不方便查看。可以加 ls -d prefix*

通过 man ls 可以看到这个 flag 的作用: -d Directories are listed as plain files (not searched recursively).

SF 上也给出了其他的解,可以用 echo prefix* 达到同样的效果

2021-05-29

今天遇到一个很 tricky 的 security issue. 客户在用我们的 provisioning 系统登陆的时候,是使用 SSO 的。前面还有一层 SAP 的授权层,叫 IDS 的。具体的 flow 可以表示为 IDS -> IAS -> Bizx. IAS 会用 email 做授权登陆。IDS 则是用 id. 但是 IDS 里面的用户可以随便更改自己的 email 就导致登陆到 Bizx 的用户可能串了。这是一个很严重的 security issue。如果真有心的话,这个 issue 说实话,可以让公司倒闭。

这个 issue 漏出去的原因还是因为这些部分分属于不同的公司维护,彼此之前的既成测试缺失,同时也不好做的缘故。

2021-08-25

遇到 bug 没关系,但是有些 bug 调查起来就是揪心。特别是那些,你在他们的调用链里。他很把锅甩给你,你还实锤不了他的这种情况。

Best Practice 说他们有个功能挂了,调用链如下 service(service1() -> myService2() -> service3()), service3 挂了,整个 transaction roll back, myService2 执行完有一个 event 会发出去。现在的情况是 myService2 roll back 了,但是据说 event 还被消费了。整的我一脸问号。event 我们也是调用的其他模块的服务,不熟。调用方的代码,我们也不熟。我就直接黑人问号了???

2021-09-22

今天和 PM 讨论一个 last minutes 修改,只是改一个网站的地址(Prov Access Contral - HCM to HXM)。从我(开发)的角度来看,只是一个无所谓的改动,看了下代码,只是 5 分钟的改动。和 PM confirm 的时候,她反问了一句,这个新网址是不是已经上线了,老的是不是已经下线了。突然意识到,这是个很关键的问题,直接关系到 fix 的优先级,之前没考虑到。姜还是老的辣,哈哈,受教。

记录一些 VSCode 常用快捷键和使用技巧,提高工作效率 (´▽`)

快捷键

  • 跳转到定义:CMD + 键盘单击
  • 从定义返回:Ctr + _ 或者 Option + CMD + 方向键
  • 快速到顶部/底部:CMD + 上方向/下方向
  • Ctrl + g: 快速跳到 x 行

很酷的操作

替换成换行

cmd + f 唤出搜索看,点击 .*, 然后,查找框输入 , 替换框输入 \n 即可

重复一行

光标停留在目标行,opt + shit + 上/下 即可,666

批量修改字符串,比如第 1,3,5 行 ‘est’ 关键字前添加 ‘T’, 即多光标操作

  1. option + 鼠标左键 自定义操作锚点
  2. cmd + d 向下选中相同的部分
  3. 选中行 shift + option + i 统一相对为止操作

在 VSCode 中复制代码并黏贴到 Outlook 等客户端时,会把背景颜色也黏贴过去,可以通过如下设置避免

1
Preference -> settings, 搜索关键字 editor.copyWithSyntaxHighlighting 然后 disable 就行了

在 VSCode 中写 markdown 时,段落过长会自动换行,有表格的时候就很难看。可以 ctrl + p 然后搜索 word wrap 关闭换行即可

插件

  • Ascii Tree Generator: 快速生产 Ascii 类型的目录树,在写文档的时候很游泳,喜欢 (´▽`)
  • Markdown All in One: 他的 format 功能简直太赞了!
  • VSCode Icons: 为目录树上中的文件添加类型图标
  • Bracket Pair Colorizer: 括号色彩标识
  • rainbow csv: CSV 文件色彩标识
  • vscode-input-sequence: 输入顺序数字,好用到飞起

通过搜索 计算机组成原理 话题话的 计算机减法 了解更多细节

概念

二进制数表示带符号值时,最高位位符号位,0表示正数,1表示负数,以 -1 为例:

反码:负数反码为其绝对值按位取反 1110
补码:负数补码等于反码 +1, -1 补码 1111

有符号的变量,内存中 1111 就表示 -1

反码,补码 这些概念都是为了方便计算机做减法而创建的,所有的数都以补码形式存在。正数的补码是本身,负数是以之前叙述的逻辑转化的数。减法结果和两个补码的加法就过时一样的。至此,我们就不必设计额外的减法器了,直接重用加法器就行了。

罗列常用语言中的数字转化方法

Python

Python 中已经集成了很多用来做这个事情的内部方法,都不需要引入额外的包,很方便。主要集中在 str.format() 和其他一些内置函数比如 int(), hex () 等

str.format 转化格式如下

1
2
3
4
5
6
7
8
format_spec     ::=  [[fill]align][sign][#][0][width][grouping_option][.precision][type]
fill ::= <any character>
align ::= "<" | ">" | "=" | "^"
sign ::= "+" | "-" | " "
width ::= digit+
grouping_option ::= "_" | ","
precision ::= digit+
type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"

一些例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 十进制 8 转化成二进制,8位宽,左对齐,空位补 -, format 里面的只能是十进制的数
'{:-<8b}'.format(8)
# '1000----'

# 0xff 转化成二进制,可以先把十六进制转成十进制,再转成二进制, 0x 可以省略
'{:b}'.format(int('0xff', 16))
# '11111111'

# bin 函数也可以用来做二进制转化,基数是10
bin(8)
# '0b1000'

# str.format 加上 # 可以变成和 bin 一样的效果
'{:#b}'.format(int('0xff', 16))
# '0b11111111'

# 内置函数 format 也可以实现和 str.format 一样的功能
format(255, '#b')
# '0b11111111'

# 再介绍一种 format 的简写形式
f'{255:#b}'
# '0b11111111'

Reference

在 Win10 下用 VSCode + WSL 开发,体验还是不错的,一开始看了下官方文档,好长,好复杂。但是实际操作下来,其实很简单,赶紧搞起来,甚香( •̀ ω •́ )✧

安装步骤

首次使用 WSL 需要做一下系统设置

1
win快捷搜索-> 启用或关闭Windows功能-> 勾选 适用于Linux的Windows子系统

开启子系统选项

到微软商城,搜所 wsl, 可以看到可用的 linux 版本,比如 kail, Ubuntu 等, 点击安装

搜索界面

安装完毕后使用敲击 win 键卡开快捷搜索,输入 wsl 回车,快速打开,第一次打开时需要配置一下子系统用户名密码信息

安装 VSCode + Remote-WSL 插件

VSCode插件

启动 WSL 子系统,默认会到 jack@DESKTOP-9TGTFK1:/mnt/c/Windows/system32$ 路径下,选一个你喜欢的路径,我这里新建了目录 vscode_dir 用来测试, 然后输入 code . 第一次输入时 WSL 会安装一些包,然后打开 VSCode。到这里基本就安装完了

WSL安装VSCode包

新打开的 remote VSCode 界面,注意左下角,如果显示的时下载的 Linux 版本就表明链接成功了

VSCode-WSL连接

Reference