那些惊到我的代码(持续更新...)

本文,我会先放出类,放出截图,可能还会写出我自己的看法。
以后,我也可以以此为鉴。

方法名驼峰+下划线并用

为什么要这样呢?
红线驼峰,绿色下划线。

我理解,某种情况下,可以提高可读性。

在这里插入图片描述

多个方法内容重复

为什么要这样呢?
我唯一能想到的,就是不确定代码会不会变,不会变的抽成方法,会变的,流程可能会改动的,暂时不进行公用。

1
2
3
2022-04-28 13:58:14 补充

测试的时候这样写我可以理解,但是真正生产中我感觉这样不好,体现不到代码复用的原则。

在这里插入图片描述

catch块里写分号

org.slf4j.helpers.Util#safeGetSystemProperty
在这里插入图片描述
为什么要这样呢?
为了可读性,大可加一行注释即可。没必要加引号的。我也是第一次见到。

下面我演示了一下,实时证明,编译会进行去除。
在这里插入图片描述

case加大括号

2021-11-09 14:35:25
在这里插入图片描述

原来 case 也可以加大括号,学到了~

静态变量的描述

2021-11-30 11:47:11
org.assertj.core.presentation.StandardRepresentation
写的非常清楚明了,让不知道这个类是干什么的,也可以看懂这些变量做什么的。
在这里插入图片描述

继承接口(向上扩展)

2021-11-30 11:49:02
java.io.Closeable
在 1.5 只有 Closeable 接口。在 1.7 的时候新加了一个接口 AutoCloseable,让 Closeable 继承 AutoCloseable。
(原本 1.5 的时候,Closeable 接口是底层功能。在 1.7 的时候,把底层功能拓展了,加了 AutoCloseable 接口)
在这里插入图片描述
在这里插入图片描述

Function.identity()

package java.util.function;
虽然这个并没有什么,写 t -> t 也是可以的(我之前就是这么写的)。但毕竟写Function.identity()更好看一些。
这里体会到封装的特性。就感觉很舒服,很漂亮的code~
在这里插入图片描述

接口默认方法抛异常

2022-01-12 18:37:04

在这里插入图片描述
为什么要这么做呢?

假设一种情况,A、B、C、D、E都实现这个接口。

A、B、C 无需对这个接口进行实现。
D、E 需要对这个接口进行实现。

设置 remove() 默认方法的话,避免了 A、B、C 要对此方法进行空实现。

嵌套延迟任务

2022-01-17 12:03:35
嵌套延时任务 => 定时任务
关于:线程池之ScheduledThreadPoolExecutor 可参考 23. 线程池之ScheduledThreadPoolExecutor
在这里插入图片描述

初始化容量 1024

2022-01-17 15:17:06

ConcurrentHashMap<Service, Service> => 应该是想当 并发 Set 来使用的。
好家伙,直接初始化 1024,这个应该是注册中心的服务单例仓库,不知道为什么要搞得那么的大。
(2022-07-18 10:16:16 补:搞那么大,是因为初始化启动的时候,不想后续再进行频繁扩容,先把坑位搞大,也方便分散均匀)
在这里插入图片描述

代码为什么没注释

2022-01-17 15:38:03

真正的代码,只有类和方法有注释。其他地方都是没有注释的。
因为好的代码,方法和变量,以及类、接口。它们就是最好的注释。如果不是,说明你定义的具有二义性。
(2022-09-26 08:14:26 补:因为好的代码都是高内聚、低耦合设计,代码方法内注释很少,但是文档注释却补充的很完善。
但我们平时开发恰恰相反,文档注释很多,甚至不写,代码中写的注释有很多。)

(后来我在此篇文章中也提到了,我对“牛逼代码的思考”。)
关于 Nacos config 长轮询的源码

多Map嵌套的可读性

2022-01-17 15:55:33
在这里插入图片描述

雪花id i++

2022-01-18 15:22:14

它应该只是想表明:我的id也是不唯一的。(不是只有雪花算法生成的id才能称之为雪花id,只要不重复就是雪花id)
在这里插入图片描述

常量值重复,名不一致

2022-01-18 15:29:22

当然了,这样写,同样也是为了区分可读性。虽然值相同,根据常量的名称不同,而适用于不同的场景。
在这里插入图片描述

饿汉单例放内部类中

》》》第一次理解
2022-01-21 08:29:42
这个单例为什么不直接放外部类中呢,而要放在内部类中。这个我不太明白。

猜测:我才猜不出来。。。我只能说私有静态内部类会加载一次,然后它的静态成员变量也会加载一次。保证只有一次创建对象。
但是你放在外部也是只有一次初始化呀,即使外部的类不是 static。我不太理解。
在这里插入图片描述

》》》第二次理解
2022-01-22 18:14:46
我又发现了一个。但是我看源码的时候也发现有很多直接放在了外部类中private static final 修饰的啊。还是搞不懂为什么要这样写。
在这里插入图片描述

》》》第三次理解
2022-04-22 02:04:08
高兴!!!
我发现了这个原因的奥秘。其实我在第一次的时候就已经说了。
(现在是上海疫情期间,此时我在家里学习,真的是上头了,现在都夜里2点了。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 它利用了关于【类初始化的语言保证】,因此可以在所有符合 Java 的编译器和虚拟机中正常工作。
//
// 内部类的引用不早于调用 getInstance() 的那一刻(因此类加载器不早于加载)。
// => 因此,该解决方案是线程安全的,不需要特殊的语言结构(即 volatile 或 synchronized)。
// 2022-04-22 02:04:08
public class Singleton {
private Singleton() {
}

private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

迭代器使用 for

2022-01-22 21:25:34

迭代器使用 for 来写,而不是 while
这样可以我是知道的,只是因为我从来没这样用过,我都是用 while。
使用起来也是差不多的,只是我第一次见到这样写,仅此而已。
在这里插入图片描述

List封装为对象

2022-01-25 09:42:16

不直接用 List<Instance> 来进行传参,而是把这个集合封装为一个对象 Instances(多了一个s)。
而在这个对象里面提供一些方法,供外部使用。(非常好的面向对象思想,值得借鉴。)
在这里插入图片描述

Retransmitter,最大重试次数,ack,耗时

2022-01-25 15:19:39

Retransmitter 从翻译可以了解到:转播发射器,中继发射器。
(也就是重新进行发射的意思)。

下面是 Nacos udp 数据包发送的一个使用场景。

  • 最大重试次数,和 ack。
    在这里插入图片描述

  • 耗时
    在这里插入图片描述

List Map.Entry

2022-01-25 17:24:11

不使用 List<Map<String, Instance>>,却使用 List<Map.Entry<String, Instance>>,…

1
2
3
4
5
6
7
8
2022-02-09 11:26:39

我想通了。

List<Map>,里面放的是 Map 类型,而 Map 类型里面占用空间大。
例如:HashMap 里面有 Entry[] 数据,LinkedHashMap 里面有 head、tail,TreeMap...

List<Map.Entry>,里面放的只是 k,v 结构的 node 节点。(占用空间小)。

在这里插入图片描述

面向对象的思想

2022-02-07 08:47:35

案例1、使用这个类来继承 Date,就可以直接使用它的格式。不用 new Date 然后再转一次,这里直接 new 即可。
在这里插入图片描述

案例2:使用多级继承的结构。符合依赖倒置。这个如果加功能的话,更方便一些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
面向对象的三大特性:封装、继承、多态

面向对象的七大基本原则:(或 五大原则,前五项)

1. 单一职责原则(Single Responsibility Principle)
每一个类应该专注于做一件事情。

2. 开闭原则(Open Close Principle)
面向扩展开放,面向修改关闭。

3. 里氏替换原则(Liskov Substitution Principle)
超类存在的地方,子类是可以替换的。

4. 依赖倒置原则(Dependence Inversion Principle)
实现尽量依赖抽象,不依赖具体实现。

5. 接口隔离原则(Interface Segregation Principle)
应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

6. 迪米特法则(Law Of Demeter)
又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。

在这里插入图片描述

static 加 synchronized

2022-02-07 09:37:33

避免还未初始化完成 (init 未执行完成),就执行了 shutdown 方法。
为了使这两个不能同时进行,所以上锁。
在这里插入图片描述

特权线程工厂 Executors.privilegedThreadFactory

2022-02-07 10:55:20

只是说与父线程具有相同的权限。设置 ac(访问控制器) 与 cl(类加载器)。

(暂时还不知道这两个有什么特别用途,看这个方法也没有在其他地方用到过。)
在这里插入图片描述

在这里插入图片描述

委托的好处

2022-02-07 10:24:38

一开始,我一直没想懂 delegate 委托的好处。后来我总结了有两个地方。(依照下面图示,我称为 “外”、“内”)

1、增减方法(扩展功能、减少功能)
原本“内”有 10个方法,但是我在“外”中只定义 3个方法。把其他方法不对外提供。同理,也可以在 10个方法上,提供额外的方法。

2、扩展功能
例如在下面图示,原本“内”只拥有②级功能。现在我让“外”继承了③级功能,这样就变相的让“内”拥有了③级功能。(也就是为了扩展功能)。

3、代码易维护
例如在下面图示,我为了使用“内”的execute方法,我把“外”也定义了一个execute方法。我的程序中到处用的都是“外”.execute,即使“内”.execute 方法改名了,改为 “内”.run 了,我只需要改“外”.execute 方法一处即可,不用修改多处。

总结:委托的本质,就是为了扩展功能、和 减少功能。

在这里插入图片描述

其实,我当时看到上面图示这些代码瞬间惊了,为什么这样???

心想:“不行,我一定要搞清楚为什么。”

然后我百度搜索了一堆,其实都没看太懂。
直接看到了一篇:设计模式-代理模式(delegate)

而此时的 CharacterProxy 类,只能对外提供 toString() 方法。这样即使外部想使用 CharSequence 的其他方法,也使用不到了。
(于是,这里我想到了《大话设计模式》里面的一句话:大致意思是说 想扩展功能可以使用代理,不想对外提供一些功能也可以使用代理。个人理解:委托也算是代理的一种。)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CharacterProxy {
// delegate 被代理
private final CharSequence delegate;

public CharacterProxy(CharSequence delegate) {
this.delegate = delegate;
}

@Override
public String toString() {
return delegate.toString();
}
}

2022-02-07 11:15:04 再举个栗子:
是不是一眼就看出来为什么了???
让④变相的增加了③⑤功能。
在这里插入图片描述

Class#getPrimitiveClass

2022-02-10 09:28:16

八大基本类型算是八种。
但是原生这个方法获取,却是 9 种。多了一个 void。

在这里插入图片描述
在这里插入图片描述

枚举单例,枚举实现接口,监听器

2022-02-11 08:05:50

第一次见到单例这么来用的,直接把枚举当做 Object 来使用。

这才是我见过最好的枚举单例。即使它不算是规规矩矩的枚举。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

枚举是天生单例的,众所周知。而且枚举是不可以反射进行创建实例的,其他都可以调用反射来创建实例。
所以,真实的情况是,安全的单例:只有枚举一种。

这里使用枚举的属性来控制,线程是否继续执行。这里我还测试了一把,枚举是单例的,但它的属性可以修改吗???是可以修改的。

下面是:“测试枚举的成员变量是否可以修改???”
其实用枚举就是为了不可变,所以,一般建议枚举是不要用可变成员变量的。
而且 sonar (代码扫描工具)建议枚举不要提供 setter 方法。只需要提供 getter 来获取属性值即可。
(所以,上面的使用并不是规范的用法,一般可以采用其他的方式来使用单例。这里就不说了。)
在这里插入图片描述

关于 hutool 监听器:
下面会存在一个问题,一旦阻塞 sync=true,这个线程就一直处于 wait(0) 状态了。
在这里插入图片描述

方法返回值泛型问题

2022-02-11 11:49:06

这个是使用的时候,我们不加类型强转。

这个是编译器自己加的。
在这里插入图片描述

静态代码块可以写多个

2022-02-18 18:01:39

第一次见到,原来还有写多个的。实际上,它们还是会被编译到一起去(从上到下编译)。
在这里插入图片描述
在这里插入图片描述

接口定义 @override 重写接口方法

2022-02-24 11:34:22

实现方法上面写 @override 是经常见到的,接口上面重新我是第一次见到。

没想懂为什么,要重新写一遍这个方法。不写也是可以的啊。

可能是开发者内部的一种规范吗???
在这里插入图片描述

ConcurrentHashMap 上synchronized锁

2022-02-25 17:13:12

我不明白为什么,右边的 1、3 都是 ConcurrentHashMap,但是中间还要上synchronized锁(this是单例的)。
即使 2 上了锁,3依然会被覆盖掉的。2好像是多于的。3也只是占个坑。
在这里插入图片描述

线程中断异常,再中断

2022-02-25 17:19:28

wait 是忽略了中断异常,而 sleep 是又中断了一次。
在这里插入图片描述

Math.random,Random,ThreadLocalRandom

2022-03-23 09:19:42

为什么要定义一个私有静态不可继承类呢?直接定义一个成员变量它不好吗? 还要多写一个类。

在 Math 类中定义一个成员变量也可以,但是这个东西貌似不属于 Math,体现了不单一。

单写一个类,体现了 类的可读性以及单一原则。

包括一些单例的时候,有的人也会定义一个私有类,在之前也写过。
直接在类中写单例行不行,也可以的。
在这里插入图片描述


后续思考。
可以看到方法上面,说到了这个方法生成一个 double 值:大于等于 0.0,小于 1(并且是伪随机的偏向于均匀分布的算法)。
并且它说这个方法是线程安全的 synchronized,但是你要告诉进行生成,会产生线程的争用。

我们来进一步分析:
在这里插入图片描述

对于以上随机生成效率不高,解决方案是什么呢?
》》》类似于 ThreadLocal 思想的,基于 Thread 类的成员变量,来做到线程隔离来避免争用。
在这里插入图片描述

内部类调用外部类

2022-03-24 18:53:20

以前我没注意过这个问题。
今天突然想到。

答案可参考:深入理解Java中为什么内部类可以访问外部类的成员

两个准则:
1、内部类对象的创建依赖于外部类对象。

2、内部类对象持有指向外部类对象的引用(参考下面编译后的图片)。

在这里插入图片描述
在这里插入图片描述

异常单例

2022-03-25 17:15:02

某些异常是可以实现单例的。例如下面的警告。
当然,还是传入指定场景信息最好,对吧。
在这里插入图片描述

do{…}while(true);

2022-03-25 17:27:49

这样写,适用于必须要走一次。(while true 在前面,好像也能表达这个意思。)
在这里插入图片描述

单例池

2022-04-30 06:41:24

原因是我看到一个方法被废弃了,我看了一下。雪花对象应为单例。
在这里插入图片描述

下面我又看了一下单例的实现,这个时候我发现了 lambda函数表达式的一个用途(防止参数下传)。
之前没发现,现在突然悟到了,就是参数不下传,可以使用回调。
在这里插入图片描述

异常定义

2022-05-11 08:55:51

无论怎么样,在能复用的情况下,最好定义异常对象。
这样使代码更友好。例如:你的权限校验异常在哪些地方会用到。一眼便知。
在这里插入图片描述
在这里插入图片描述

SPI机制的数据提供者

2022-05-11 08:58:55

我的天呐,这是缘分吗。怎么会那么的巧呢。

前两天我在写预警中心,发送服务逻辑的时候。
正好我最近在看 datart 的取数逻辑。

虽然都是一样的,但是实现方式是完全不同的,而且我的逻辑相对来说比较单一,直接用类进行区分。这里使用SPI机制来设计,分module 来设计,完全的解耦了。可选择性依赖。插件式扩展服务。
(2022-06-18 21:18:19 其实网上大部分说的SPI都是jdbc,以及Dubbo)
在这里插入图片描述
在这里插入图片描述

Exceptions.throw

2022-05-23 18:50:42

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
36
37
38
39
40
41
42
43

package datart.core.base.exception;

import datart.core.common.MessageResolver;

import java.lang.reflect.Constructor;

public class Exceptions {

public static void msg(String msg, String... code) {
tr(BaseException.class, msg, code);
}

public static void base(String msg) {
throw new BaseException(msg);
}

public static void notFound(String... msg) {
tr(NotFoundException.class, "base.not.exists", msg);
}

public static void exists(String... msg) {
tr(ParamException.class, "base.not.exists", msg);
}

public static void e(Exception e) {
throw new BaseException(e);
}

public static void tr(Class<? extends BaseException> clz, String messageCode, String... codes) throws RuntimeException {
BaseException throwable;
try {
String message = MessageResolver.getMessages(messageCode, (Object[]) codes);// codes 是填充参数的
Constructor<? extends BaseException> constructor = clz.getConstructor(String.class);
throwable = constructor.newInstance(message);
} catch (Exception e) {
throwable = new BaseException(messageCode);
}
throw throwable;
}


}
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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class MessageResolver {

private static MessageSource messageSource;

public MessageResolver() {
}

@Autowired
public void setMessageSource(MessageSource messageSource) {
MessageResolver.messageSource = messageSource;
}

public static String getMessage(Object code) {
return messageSource.getMessage(code.toString(), null, code.toString(), LocaleContextHolder.getLocale());
}

// public static String getMessage(String code, Object... args) {
// return messageSource.getMessage(code, args, code, LocaleContextHolder.getLocale());
// }

public static String getMessages(Object code, Object... messageCodes) {
Object[] objs = Arrays.stream(messageCodes).map(MessageResolver::getMessage).toArray();// 参数补充 {0} {1} 这种
return messageSource.getMessage(code.toString(), objs, code.toString(), LocaleContextHolder.getLocale());
// return getMessage(code, objs);
}
}

在这里插入图片描述

枚举$数字开头

2022-06-08 07:59:19
在这里插入图片描述

插入、更新数据

2022-06-12 18:15:08
在这里插入图片描述

Map 语法糖

2022-06-28 09:47:00

1
Map {{}}  语法糖

在这里插入图片描述

2022-07-06 17:07:48 什么鸡儿语法糖,这就是匿名内部类,可以在 {} 里面重写方法,只不过在 {} 里面写了一个构造代码块而已。

日志本地彩色,文件非彩色

2022-07-05 15:01:10

一开始,我设置了彩色,本地很漂亮,发布测试环境上去发现显示不友好,我就把彩色去除了。
我忘记了,本地彩色,测试环境非彩色。
在这里插入图片描述

测试 Kafka

2022-07-05 15:47:55

我都是用kafka那个脚本测试,第一次见到有人代码这样单元测试来搞。
在这里插入图片描述

记录异步

2022-07-09 20:08:35

在这里插入图片描述

来一张图片理解一下:
在这里插入图片描述

第一次见到这种注释

2022-07-16 16:53:51

在这里插入图片描述

Lambda函数的柯里化

2022-07-16 18:48:07

在这里插入图片描述

下面演示一下: 4+2=6
在这里插入图片描述

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 2022-07-16 19:29:39 Lambda函数的柯里化
static void currying() {
Function<Integer, Function<Integer, Function<Integer, Integer>>> currying0 = new Function<Integer, Function<Integer, Function<Integer, Integer>>>() {
@Override
public Function<Integer, Function<Integer, Integer>> apply(Integer x) {
return new Function<Integer, Function<Integer, Integer>>() {
@Override
public Function<Integer, Integer> apply(Integer y) {
return new Function<Integer, Integer>() {
@Override
public Integer apply(Integer z) {
return x + y - z;
}
};
}
};
}
};
Function<Integer, Function<Integer, Function<Integer, Integer>>> currying1 = new Function<Integer, Function<Integer, Function<Integer, Integer>>>() {
@Override
public Function<Integer, Function<Integer, Integer>> apply(Integer x) {
return new Function<Integer, Function<Integer, Integer>>() {
@Override
public Function<Integer, Integer> apply(Integer y) {
return z -> x + y - z;
}
};
}
};
Function<Integer, Function<Integer, Function<Integer, Integer>>> currying2 = new Function<Integer, Function<Integer, Function<Integer, Integer>>>() {
@Override
public Function<Integer, Function<Integer, Integer>> apply(Integer x) {
return y -> z -> x + y - z;
}
};
Function<Integer, Function<Integer, Function<Integer, Integer>>> currying3 = x -> y -> z -> x + y - z;
// 可参考 => Function2#curried() 柯里化版本

int x = 5;
int y = 4;
int z = 3;
// x + y - z
// 5 + 4 - 3 = 6
Integer apply0 = currying0.apply(x).apply(y).apply(z);// 6
Integer apply1 = currying1.apply(x).apply(y).apply(z);// 6
Integer apply2 = currying2.apply(x).apply(y).apply(z);// 6
Integer apply3 = currying3.apply(x).apply(y).apply(z);// 6

// Lambda函数的柯里化
System.out.println();
}

Lambda函数的 & ZAM接口

2022-07-18 10:13:17
记忆化的实现我知道,下面也很容易理解,就是绿色的部分,实现懒加载,但是红色的部分更是让我很好奇。

我在 JavaSE 官方文档 —> 泛型 —> 多重有界的类型参数中,找到了答案。

在这里插入图片描述

我们来实现一个标签化

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
// java中的lambda,需要先定义一个 只有一个抽象方法的接口,称为SAM类型,
@FunctionalInterface//SAM接口注解
interface SAM{
public int F(int x);//只能有一个抽象函数
default int G(int x){//java8中,可以有默认实现函数
return -1;
}
}
SAM sam = (params)->{ body; };//实现 SAM.F()方法,返回一个接口实现后的对象


//1.抽象方法F只有一个参数,则()可省略,params参数类型可省略
//2.若返回值为void且只有一条语句时,{}可省略
//3.若抽象方法 F体内 需要使用局部变量(直接使用),则参数一定是隐式final的,不可二次赋值(全局的类变量没有这个限制)
//4.默认情况下,Lambda表达式不能序列化,引入"类型关联" lambda & ZAM,相当于实现了ZAM接口,ZAM(zero abstract method)



//5.若抽象方法F(args)的实现代码 仅是 调用另一个方法G(args),且F(agrs)的参数和G(args)的参数一样,那么可直接用G代替lambda表达式,G叫做方法引用
F(String s){
System.out.println(s);
}
//等同于:(s)->System.out.println(s);
System.out::println //代表println参数为s,注意作用域符::


//6.lambda方法,字节码下方法名是: Lambda$0



// JAVA定义的SAM接口
Function:R apply(T t) ; //对传入的 类型为T的参数t,操作后 返回一个类型为R的值
Consumer:void accept(T t) ; //对传入的参数t,执行操作
Predicate:boolean test(T t) ; //对传入的参数t,判断是否满足条件
Supplier:T get() ; //新建一个元素,返回

在这里插入图片描述

Lambda的方法引用类型问题

2022-07-18 10:13:52

Lambda 表达式 — Oracle 官方文档 — Lambda Expressions (The Java™ Tutorials > Learning the Java Language > Classes and Objects) 2022-07-16 18:00:29
Lambda 表达式 方法引用 — Oracle 官方文档 — Method References (The Java™ Tutorials > Learning the Java Language > Classes and Objects) 2022-07-16 18:05:41

先把官方文档放在上面。

下面这个文档注释中的type3 表达的意思是什么,我到现在还不清楚。
在这里插入图片描述

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
// 2022-07-18 10:25 方法引用测试
public static void main(String[] args) throws Exception {
Function1<Integer, Integer> f1 = Function1.of(i -> i + 1); // f1 = {MyVavrTest$lambda@665}
Function1<Integer, Integer> f2 = Function1.of(MyVavrTest::addOne); // f2 = {MyVavrTest$lambda@666}
Function1<Integer, Integer> f3 = Function1.of(f1); // f3 = {MyVavrTest$lambda@665}
Function1<Integer, Integer> f4 = Function1.of(f1::apply); // f4 = {MyVavrTest$lambda@667}

Class<? extends Function1> f1_class = f1.getClass();// f1_class = {Class@651} "class com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$1/1310540333"
Class<? extends Function1> f2_class = f2.getClass();// f2_class = {Class@657} "class com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$2/1340328248"
Class<? extends Function1> f3_class = f3.getClass();// f3_class = {Class@651} "class com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$1/1310540333"
Class<? extends Function1> f4_class = f4.getClass();// f4_class = {Class@661} "class com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$3/540642172"

String f1_typeName = f1.getClass().getTypeName();// f1_typeName = "com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$1/1310540333"
String f2_typeName = f2.getClass().getTypeName();// f2_typeName = "com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$2/1340328248"
String f3_typeName = f3.getClass().getTypeName();// f3_typeName = "com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$1/1310540333"
String f4_typeName = f4.getClass().getTypeName();// f4_typeName = "com.taopanfeng.junit.vavr.MyVavrTest$$Lambda$3/540642172"

Class<?> f1_componentType = f1.getClass().getComponentType();// null
Class<?> f2_componentType = f2.getClass().getComponentType();// null
Class<?> f3_componentType = f3.getClass().getComponentType();// null
Class<?> f4_componentType = f4.getClass().getComponentType();// null
}

public static Integer addOne(Integer i) {
return i + 1;
}

对了,方法引用还可以这样。
在这里插入图片描述

常量字段引用问题

2022-07-18 10:42:47

去年我拿着这个问题,我问了我同事 孙凯隆,但是他也似懂非懂,也没说出来什么所以然。
今天我看了一下注释,难道我当初没看注释吗?对于这个我没有实际的例子,如果你有很好的案例请发给我,谢谢你。
在这里插入图片描述

在刚才邹俊问的我的时候,很庆幸,我突然领悟到了,并且示出了demo。
在这里插入图片描述

枚举单例应用

2022-07-22 20:31:37
真正意义上的单例。我知道有这么一种,但是在JDK源码中还是第一次见到这种写法。
在这里插入图片描述

方法里面代码块的变量名重复问题

2022-07-27 18:50:34
在这里插入图片描述

枚举不大写

2022-08-05 18:21:19

代码是你的,你爱怎么玩就怎么玩。写出来的东西,用的人多,大家认可你的产品才是最好的,代码规范次要。
在这里插入图片描述

ArrayList 数组是 transient

2022-09-02 15:38:06

优化做到极致,假设数组 length 是 10,里面只有1个元素(size=1),那么我就只序列化这一个元素。
在这里插入图片描述

类里面 ThreadLocal

2022-09-16 14:44:11

不单独写一个类了,直接写在自己类里面。
这样也比较方便,感觉这样挺好的,即使类没有分离。
在这里插入图片描述

使用静态获取Bean中的DAO

2022-09-15 10:23:04

1
2
3
4
5
6
7
8
9
10
11
关于更新插入的问题之前已经讨论过了。上次看到的是 Quartz 心跳检测这一块。

# 1. 每次执行两次 DB操作
select
!= null update
== null insert

# 2. 首次插入执行两次 DB操作,后续更新都执行一次 DB操作
update
> 0 成功
<= 0 insert

在这里插入图片描述

2022-09-23 18:29:24 这里我们是可以玩一个骚的。
所有类都不要任何注入,所有的类全部注入到一个类中。
使用一个类的静态方法来进行调用那些注入的成员变量。

使用:$.beanName()来进行调用,这样有什么好处呢?不用每个类都要写 @Autowired Xxx xxx;

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
36
37
38
39
40
41
42
43
44
45
package com.amoros.hawkeye;

import cn.hutool.extra.spring.SpringUtil;
import com.amoros.hawkeye.acl.message.service.MessageService;
import com.amoros.hawkeye.acl.stem.service.SysOrgStructureApiService;
import com.amoros.hawkeye.acl.stem.service.SysUserApiService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
* 动态调用 Bean
*
* @author 陶攀峰
* @date 2022-09-23 18:32
*/
@Component
public class $ implements InitializingBean {

public static $ _$;

@Override
public void afterPropertiesSet() throws Exception {
_$ = SpringUtil.getBean($.class);
}

@Autowired MessageService messageService;
@Autowired SysUserApiService sysUserApiService;
@Autowired SysOrgStructureApiService sysOrgStructureApiService;

//----------------------------------------------------------------

public static MessageService messageService() {
return _$.messageService;
}

public static SysUserApiService sysUserApiService() {
return _$.sysUserApiService;
}

public static SysOrgStructureApiService sysOrgStructureApiService() {
return _$.sysOrgStructureApiService;
}

}

静态注入

2022-10-13 14:23:58

我之前都是实现 InitializingBean 接口来实现,今天看到这个实现方式。
也就是 setter 来实现静态注入。
在这里插入图片描述

of泛型数组

2022-10-20 09:31:47
在这里插入图片描述

获取Main方法所在的Class类

2022-11-08 09:41:00

1
2
3
4
我想在 D.d() 方法中获取 main方法所在的Class类,应该怎么办?

SpringBoot 使用异常栈帧,循环比较方法名的方式,来进行获取。
===> 这样虽然是有问题的,但是SpringBoot一般上传是 main方法不会嵌套 其他的main,这样也可以的。

在这里插入图片描述

@Deprecated 已弃用 版本升级问题

2022-11-08 14:37:55

在这里插入图片描述

异常处理 — 应该永远不要到这里

2022-11-08 16:01:52

哈哈哈,代码是你的,这样也没毛病,纯粹是语法问题
在这里插入图片描述

单例内部类

2022-11-09 09:26:38

记得以前也记录过单例内部类,这里再记录一次吧。因为我看到了,hutool 上面的详细注释。

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
// cn.hutool.core.convert.ConverterRegistry
public class ConverterRegistry implements Serializable {
private static final long serialVersionUID = 1L;

// ...省略代码

/**
* 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 没有绑定关系,而且只有被调用到才会装载,从而实现了延迟加载
*/
private static class SingletonHolder {
/**
* 静态初始化器,由JVM来保证线程安全
*/
private static final ConverterRegistry INSTANCE = new ConverterRegistry();
}

/**
* 获得单例的 ConverterRegistry
*
* @return ConverterRegistry
*/
public static ConverterRegistry getInstance() {
return SingletonHolder.INSTANCE;
}

// ...省略代码
}

Type 和 Class 为什么并存???

2022-11-09 09:01:50

1
2
3
4
5
6
7
8
9
10
11
看到 Spring事件推送的时候,使用  ResolvableType来管理,事件类型对应的 ApplicationListener监听器。
避免泛型,导致推送事件给所有的 ApplicationListener监听器。

Class 是 Type 接口的实现类,为什么要保存两种成员变量呢???
例如:就好比成员变量既有 List 又有 ArrayList,而且变量指针都指向 ArrayList,这不就很奇怪吗???

想到这里,我想到了我以前在研究 为什么 JSON 需要 TypeReference<T> 接口的时候,就有用到 Type 而不是 Class,
借此疑问,我把 JSON 解析又重新 Debug 了一下,对它底层有了更深入的了解,并且参考网上文章 + 自己 Debug,知道了 Type如何管理泛型。
网上文章(排版不太好,但是内容还可以):
type接口和class的区别(类型和类)
https://blog.csdn.net/ZytheMoon/article/details/79241988

在这里插入图片描述

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
// 2022-11-09 09:01 TypeReference Type 类型引用问题 => Json 字符串转换
/*public static void main(String[] args) throws Exception {
// type接口和class的区别(类型和类) =====> https://blog.csdn.net/ZytheMoon/article/details/79241988
List<Map<String, Object>> queryResult = new ArrayList<>();
Class cl = queryResult.getClass();// java.util.ArrayList
Type typeArgument = TypeUtil.getTypeArgument(queryResult.getClass());// E
String typeName = cl.getTypeName();// java.util.ArrayList
Type genericSuperclass = cl.getGenericSuperclass();// java.util.AbstractList<E> =====> sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
String genericString = cl.toGenericString();// public class java.util.ArrayList<E>

Type[] genericInterfaces = cl.getGenericInterfaces();
// 0 = {ParameterizedTypeImpl@1095} "java.util.List<E>"
// 1 = {Class@237} "interface java.util.RandomAccess"
// 2 = {Class@336} "interface java.lang.Cloneable"
// 3 = {Class@344} "interface java.io.Serializable"

// ----------------------------------------------------------------------------

TypeReference<List<Map<String, Student>>> typeReference = new TypeReference<List<Map<String, Student>>>() {
};
Type type = typeReference.getType();// java.util.List<java.util.Map<java.lang.String, com.taopanfeng.junit.web.Student>>

// [{"123456":{"name":"陶攀峰"}}]
List<Map<String, Student>> maps = JSONUtil.toBean("[{\"123456\":{\"name\":\"陶攀峰\"}}]", typeReference, false);
// JSONUtil.toBean("[{\"123456\":{\"name\":\"陶攀峰\"}}]", List.class);// cn.hutool.json.JSONException: A JSONObject text must begin with '{' at 1 [character 2 line 1]
}*/

isAssignableFrom 与 instanceof

2022-11-14 08:35:01

Class 使用 isAssignableFrom,实例化对象使用 instanceof
在这里插入图片描述

德摩根公式

2023-01-11 09:48:15

具体可参考:德摩根定律
在这里插入图片描述

异常的再次思考

2023-03-23 14:22:41

原本我认为 throw e; 如果e不属于RuntimeException的话,必须要处理或者在方法加 throws 扔出去。

案例1、e1()方法,catch 住,可以 throw 非RuntimeException。

案例2、e2()方法,catch 住,不可以 throw 非RuntimeException(必须要处理 或 包装为 RuntimeException 或 throws 出去)。
在这里插入图片描述

泛型方法匹配问题

首次碰到这个问题是 datart 中 2022-09-16 18:49
在这里插入图片描述

恰好 ck 又支持 IN 中有大括号(下面两种写法在 ck中都可以)

1
2
3
AND store_id IN (1,4)

AND store_id IN ([1,4])

留稿(之前也写过一次,但不知道放在了哪里了)
也可参考:Java基础总结 - 泛型

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
// 2023-03-23 14:44 ? extends super 泛型方法匹配问题 再回顾
public static void main(String[] args) throws Exception {
List<Long> longList = new ArrayList<>();
Collection<Number> numberCollection = new ArrayList<>();

T(longList);
T(numberCollection);


// 关于泛型匹配问题
// 元素匹配
// 1. 唯一
// 2. 全 模糊
// 3. extends 模糊
// 4. super 模糊
// 接口匹配 => 参数是传入的子类、接口
}

public static void T(Object value) {
}

public static void T(Collection<Object> value) {
// public static void T(Collection<Long> value) {
// public static void T(Collection<Number> value) {
}

public static void T(List<Number> value) {
// public static void T(List<Object> value) {
// public static void T(List<Long> value) {
// public static void T(List<?> value) {
// public static void T(List<? extends Number> value) {
// public static void T(List<? extends Object> value) {// 等同于 List<?> value
}

泛型feign调用问题

传入保证类型只要是集合就没问题,因为 feign会被序列化/反序列化。
(A调用 B.b(T t) 假设参数 T是个 List,你传入一个 Set 完全没问题)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 2023-03-23 15:59 泛型feign调用问题
public static void main(String[] args) throws Exception {
Set<Long> data = new HashSet<>();

ComReq of = ComReq.of(data);
feign(of);
}

public static void feign(ComReq<List<Long>> comReq) {
System.out.println("发起请求...");
comReq.data.set(0, 1L);
}

public static class ComReq<T> {
public T data;

public static <T> ComReq<T> of(T data) {
ComReq<T> comReq = new ComReq<>();
comReq.data = data;
return comReq;
}
}

抽象方法 getSelf

2023-06-06 10:19:18

一开始看到这个抽象类,并且还说 getSelf,而继承这个抽象类的呢,重写返回 this。
这有什么用呢,再仔细一看,大有道理。
“抽象方法 getSelf,而非this” 这样可以使具体的实现类,可以调用基础方法并返回自己,实现链式调用,并且返回的是实现类。
让我想到了之前我重写了 Row 继承了 Dict 使用其中的 set 返回的是 Dict 而非 Row。因此我又重写了一个 set方法。
在这里插入图片描述

GetMapping路径参数映射对象问题

2023-12-20 18:14:51

这是 springboot一直支持的,但这是我第一次见到这种用法。
在这里插入图片描述

vite前端代理解决跨域问题

2023-12-20 15:22:42

原来前端也可以做代理,这样浏览器还不会拦截到。
(可简单理解为一个隐藏的 nginx)
(好比,你请求了 3000端口的 controller, controller 内部发送 http 到 8080端口到别的服务,把结果返回给 3000端口。)
在这里插入图片描述

Func0 throws Exception

2024-03-28 11:50:31

Func0 throws Exception(只有使用的时候才会抛出异常,并且可以包装为 RuntimeException 方法)
在这里插入图片描述

多个静态代码块 静态变量写在一起

2024-04-11 11:42:41

第一次见到 这种写法,看着挺舒服的,不用找这个 静态变量在哪里初始化的了。(可以借鉴)
在这里插入图片描述