开发中造成空指针的常见用法,如何避免
1. 前言
《手册》的第 7 页和 25 页有两段关于空指针的描述:
【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:
- 返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE。
反例:public int f () { return Integer 对象}, 如果为 null,自动解箱抛 NPE。
数据库的查询结果可能为 null。
集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。
远程调用返回对象时,一律要求进行空指针判断,防止 NPE。
对于 Session 中获取的数据,建议进行 NPE 检查,避免空指针。
级联调用 obj.getA ().getB ().getC (); 一连串调用,易产生 NPE。
《手册》对空指针常见的原因和基本的避免空指针异常的方式给了介绍,非常有参考价值。
那么我们思考以下几个问题:
- 如何学习
NullPointerException(简称为 NPE)? - 哪些用法可能造 NPE 相关的 BUG?
- 在业务开发中作为接口提供者和使用者如何更有效地避免空指针呢?
2. 了解空指针
2.1 源码注释
前面介绍过源码是学习的一个重要途径,我们一起看看 NullPointerException 的源码:
/*** Thrown when an application attempts to use {@code null} in a* case where an object is required. These include:* <ul>* <li>Calling the instance method of a {@code null} object.* <li>Accessing or modifying the field of a {@code null} object.* <li>Taking the length of {@code null} as if it were an array.* <li>Accessing or modifying the slots of {@code null} as if it* were an array.* <li>Throwing {@code null} as if it were a {@code Throwable}* value.* </ul>* <p>* Applications should throw instances of this class to indicate* other illegal uses of the {@code null} object.** {@code NullPointerException} objects may be constructed by the* virtual machine as if {@linkplain Throwable#Throwable(String,* Throwable, boolean, boolean) suppression were disabled and/or the* stack trace was not writable}.** @author unascribed* @since JDK1.0*/
public
class NullPointerException extends RuntimeException {private static final long serialVersionUID = 5162710183389028792L;/*** Constructs a {@code NullPointerException} with no detail message.*/public NullPointerException() {super();}/*** Constructs a {@code NullPointerException} with the specified* detail message.** @param s the detail message.*/public NullPointerException(String s) {super(s);}
}
源码注释给出了非常详尽地解释:
空指针发生的原因是应用需要一个对象时却传入了
null,包含以下几种情况:
- 调用 null 对象的实例方法。
- 访问或者修改 null 对象的属性。
- 获取值为 null 的数组的长度。
- 访问或者修改值为 null 的二维数组的列时。
- 把 null 当做 Throwable 对象抛出时。
实际编写代码时,产生空指针的原因都是这些情况或者这些情况的变种。
《手册》中的另外一处描述
“集合里的元素即使 isNotEmpty,取出的数据元素也可能为
null。”
和第 4 条非常类似。
如《手册》中的:
“级联调用 obj.getA ().getB ().getC (); 一连串调用,易产生 NPE。”
和第 1 条很类似,因为每一层都可能得到 null 。
当遇到《手册》中和源码注释中所描述的这些场景时,要注意预防空指针。
另外通过读源码注释我们还得到了 “意外发现”,JVM 也可能会通过 Throwable#Throwable(String, Throwable, boolean, boolean) 构造函数来构造 NullPointerException 对象。
2.2 继承体系
通过源码可以看到 NPE 继承自 RuntimeException 我们可以通过 IDEA 的 “Java Class Diagram” 来查看类的继承体系。

可以清晰地看到 NPE 继承自 RuntimeException ,另外我们选取 NoSuchFieldException 和 NoSuchFieldError 和 NoClassDefFoundError ,可以看到 Throwable 的子类型包括 Error 和 Exception, 其中 NPE 又是 Exception 的子类。
那么为什么 Exception 和 Error 有什么区别? Excption 又分为哪些类型呢?
我们可以分别去 java.lang.Exception 和 java.lang.Error 的源码注释中寻找答案。
通过 Exception 的源码注释我们了解到, Exception 分为两类一种是非受检异常(uncheked exceptions)即 java.lang.RuntimeException 以及其子类;而受检异常(checked exceptions)的抛出需要再普通函数或构造方法上通过 throws 声明。
通过 java.lang.Error 的源码注释我们了解到,Error 代表严重的问题,不应该被程序 try-catch。编译时异常检测时, Error 也被视为不可检异常(uncheked exceptions)。
大家可以在 IDEA 中分别查看 Exception 和 Error 的子类,了解自己开发中常遇到的异常都属于哪个分类。
我们还可以通过《JLS》2 第 11 章 Exceptions 对异常进行学习。
其中在异常的类型这里,讲到:
不可检异常( unchecked exception)包括运行时异常和 error 类。
可检异常( checked exception )不属于不可检异常的所有异常都是可检异常。除 RuntimeException 和其子类,以及 Error 类以及其子类外的其他 Throwable 的子类。

还有更多关于异常的详细描述,,包括异常的原因、异步异常、异常的编译时检查等,大家可以自己进一步学习。
3. 空指针引发的血案
3.1 最常见的错误姿势
@Testpublic void test() {Assertions.assertThrows(NullPointerException.class, () -> {List<UserDTO> users = new ArrayList<>();users.add(new UserDTO(1L, 3));users.add(new UserDTO(2L, null));users.add(new UserDTO(3L, 3));send(users);});}// 第 1 处private void send(List<UserDTO> users) {for (UserDTO userDto : users) {doSend(userDto);}}private static final Integer SOME_TYPE = 2;private void doSend(UserDTO userDTO) {String target = "default";// 第 2 处if (!userDTO.getType().equals(SOME_TYPE)) {target = getTarget(userDTO.getType());}System.out.println(String.format("userNo:%s, 发送到%s成功", userDTO, target));}private String getTarget(Integer type) {return type + "号基地";}
在第 1 处,如果集合为 null 则会抛空指针;
在第 2 处,如果 type 属性为 null 则会抛空指针异常,导致后续都发送失败。
大家看这个例子觉得很简单,看到输入的参数有 null 本能地就会考虑空指针问题,但是自己写代码时你并不知道上游是否会有 null。
3. 2 无结果仍返回对象
实际开发中有些同学会有一些非常 “个性” 的写法。
为了避免空指针或避免检查到 null 参数抛异常,直接返回一个空参构造函数创建的对象。
类似下面的做法:
/*** 根据订单编号查询订单** @param orderNo 订单编号* @return 订单*/
public Order getByOrderNo(String orderNo) {if (StringUtils.isEmpty(orderNo)) {return new Order();}// 查询orderreturn doGetByOrderNo(orderNo);
}
由于常见的单个数据的查询接口,参数检查不符时会抛异常或者返回 null。 极少有上述的写法,因此调用方的惯例是判断结果不为 null 就使用其中的属性。
这个哥们这么写之后,上层判断返回值不为 null , 上层就放心大胆得调用实例函数,导致线上报空指针,就造成了线上 BUG。
3.3 新增 @NonNull 属性反序列化的 BUG
假如有一个订单更新的 RPC 接口,该接口有一个 OrderUpdateParam 参数,之前有两个属性一个是 id 一个是 name 。在某个需求时,新增了一个 extra 属性,且该字段一定不能为 null 。
采用 lombok 的 @NonNull 注解来避免空指针:
import lombok.Data;
import lombok.NonNull;import java.io.Serializable;@Data
public class OrderUpdateParam implements Serializable {private static final long serialVersionUID = 3240762365557530541L;private Long id;private String name;// 其它属性// 新增的属性@NonNullprivate String extra;
}
上线后导致没有使用最新 jar 包的服务对该接口的 RPC 调用报错。
我们来分析一下原因,在 IDEA 的 target - classes 目录下找到 DEMO 编译后的 class 文件,IDEA 会自动帮我们反编译:
public class OrderUpdateParam implements Serializable {private static final long serialVersionUID = 3240762365557530541L;private Long id;private String name;@NonNullprivate String extra;public OrderUpdateParam(@NonNull final String extra) {if (extra == null) {throw new NullPointerException("extra is marked non-null but is null");} else {this.extra = extra;}}@NonNullpublic String getExtra() {return this.extra;}public void setExtra(@NonNull final String extra) {if (extra == null) {throw new NullPointerException("extra is marked non-null but is null");} else {this.extra = extra;}}// 其他代码}
我们还可以使用反编译工具:JD-GUI 对编译后的 class 文件进行反编译,查看源码。
由于调用方调用的是不含 extra 属性的 jar 包,并且序列化编号是一致的,反序列化时会抛出 NPE。
Caused by: java.lang.NullPointerException: extra at com.xxx.OrderUpdateParam.<init>(OrderUpdateParam.java:21)
RPC 参数新增 lombok 的 @NonNull 注解时,要考虑调用方是否及时更新 jar 包,避免出现空指针。
3.4 自动拆箱导致空指针
前面章节讲到了对象转换,如果我们下面的 GoodCreateDTO 是我们自己服务的对象, 而 GoodCreateParam 是我们调用服务的参数对象。
@Data
public class GoodCreateDTO {private String title;private Long price;private Long count;
}@Data
public class GoodCreateParam implements Serializable {private static final long serialVersionUID = -560222124628416274L;private String title;private long price;private long count;
}
其中 GoodCreateDTO 的 count 属性在我们系统中是非必传参数,本系统可能为 null。
如果我们没有拉取源码的习惯,直接通过前面的转换工具类去转换。
我们潜意识会认为外部接口的对象类型也都是包装类型,这时候很容易因为转换出现 NPE 而导致线上 BUG。
public class GoodCreateConverter {public static GoodCreateParam convertToParam(GoodCreateDTO goodCreateDTO) {if (goodCreateDTO == null) {return null;}GoodCreateParam goodCreateParam = new GoodCreateParam();goodCreateParam.setTitle(goodCreateDTO.getTitle());goodCreateParam.setPrice(goodCreateDTO.getPrice());goodCreateParam.setCount(goodCreateDTO.getCount());return goodCreateParam;}
}
当转换器执行到 goodCreateParam.setCount(goodCreateDTO.getCount()); 会自动拆箱会报空指针。
当 GoodCreateDTO 的 count 属性为 null 时,自动拆箱将报空指针。
再看一个花样踩坑的例子:
我们作为使用方调用如下的二方服务接口:
public Boolean someRemoteCall();
然后自以为对方肯定会返回 TRUE 或 FALSE,然后直接拿来作为判断条件或者转为基本类型,如果返回的是 null,则会报空指针异常:
if (someRemoteCall()) {// 业务代码}
大家看示例的时候可能认为这种情况很简单,自己开发的时候肯定会注意,但是往往事实并非如此。
希望大家可以掌握常见的可能发生空指针场景,在开发是注意预防。
3.5 分批调用合并结果时空指针
大家再看下面这个经典的例子。
因为某些批量查询的二方接口在数据较大时容易超时,因此可以分为小批次调用。
下面封装一个将 List 数据拆分成每 size 个一批数据,去调用 function RPC 接口,然后将结果合并。
public static <T, V> List<V> partitionCallList(List<T> dataList, int size, Function<List<T>, List<V>> function) {if (CollectionUtils.isEmpty(dataList)) {return new ArrayList<>(0);}Preconditions.checkArgument(size > 0, "size 必须大于0");return Lists.partition(dataList, size).stream().map(function).reduce(new ArrayList<>(),(resultList1, resultList2) -> {resultList1.addAll(resultList2);return resultList1;});}
看着挺对,没啥问题,其实则不然。
设想一下,如果某一个批次请求无数据,不是返回空集合而是 null,会怎样?
很不幸,又一个空指针异常向你飞来 …
此时要根据具体业务场景来判断如何处理这里可能产生的空指针异常。
如果在某个场景中,返回值为 null 是一定不允许的行为,可以在 function 函数中对结果进行检查,如果结果为 null,可抛异常。
如果是允许的,在调用 map 后,可以过滤 null :
// 省略前面代码
.map(function)
.filter(Objects::nonNull)
// 省略后续代码
4. 预防空指针的一些方法
NPE 造成的线上 BUG 还有很多种形式,如何预防空指针很重要。
下面将介绍几种预防 NPE 的一些常见方法:

4.1 接口提供者角度
4.1.1 返回空集合
如果参数不符合要求直接返回空集合,底层的函数也使用一致的方式:
public List<Order> getByOrderName(String name) {if (StringUtils.isNotEmpty(name)) {return doGetByOrderName(name);}return Collections.emptyList();
}
4.1.2 使用 Optional
Optional 是 Java 8 引入的特性,返回一个 Optional 则明确告诉使用者结果可能为空:
public Optional<Order> getByOrderId(Long orderId) {return Optional.ofNullable(doGetByOrderId(orderId));
}
如果大家感兴趣可以进入 Optional 的源码,结合前面介绍的 codota 工具进行深入学习,也可以结合《Java 8 实战》的相关章节进行学习。
4.1.3 使用空对象设计模式
该设计模式为了解决 NPE 产生原因的第 1 条 “调用 null 对象的实例方法”。
在编写业务代码时为了避免 NPE 经常需要先判空再执行实例方法:
public void doSomeOperation(Operation operation) {int a = 5;int b = 6;if (operation != null) {operation.execute(a, b);}
}
《设计模式之禅》(第二版)554 页在拓展篇讲述了 “空对象模式”。
可以构造一个 NullXXX 类拓展自某个接口, 这样这个接口需要为 null 时,直接返回该对象即可:
public class NullOperation implements Operation {@Overridepublic void execute(int a, int b) {// do nothing}
}
这样上面的判空操作就不再有必要, 因为我们在需要出现 null 的地方都统一返回 NullOperation,而且对应的对象方法都是有的:
public void doSomeOperation(Operation operation) {int a = 5;int b = 6;operation.execute(a, b);
}
4.2 接口使用者角度
讲完了接口的编写者该怎么做,我们讲讲接口的使用者该如何避免 NPE 。
4.2.1 null 检查
正如《代码简洁之道》第 7.8 节 “别传 null 值” 中所要表达的意义:
可以进行参数检查,对不满足的条件抛出异常。
直接在使用前对不能为 null 的和不满足业务要求的条件进行检查,是一种最简单最常见的做法。
通过防御性参数检测,可以极大降低出错的概率,提高程序的健壮性:
@Overridepublic void updateOrder(OrderUpdateParam orderUpdateParam) {checkUpdateParam(orderUpdateParam);doUpdate(orderUpdateParam);}private void checkUpdateParam(OrderUpdateParam orderUpdateParam) {if (orderUpdateParam == null) {throw new IllegalArgumentException("参数不能为空");}Long id = orderUpdateParam.getId();String name = orderUpdateParam.getName();if (id == null) {throw new IllegalArgumentException("id不能为空");}if (name == null) {throw new IllegalArgumentException("name不能为空");}}
JDK 和各种开源框架中可以找到很多这种模式,java.util.concurrent.ThreadPoolExecutor#execute 就是采用这种模式。
public void execute(Runnable command) {if (command == null)throw new NullPointerException();// 其他代码}
以及 org.springframework.context.support.AbstractApplicationContext#assertBeanFactoryActive
protected void assertBeanFactoryActive() {if (!this.active.get()) {if (this.closed.get()) {throw new IllegalStateException(getDisplayName() + " has been closed already");}else {throw new IllegalStateException(getDisplayName() + " has not been refreshed yet");}}
}
4.2.2 使用 Objects
可以使用 Java 7 引入的 Objects 类,来简化判空抛出空指针的代码。
使用方法如下:
private void checkUpdateParam2(OrderUpdateParam orderUpdateParam) {Objects.requireNonNull(orderUpdateParam);Objects.requireNonNull(orderUpdateParam.getId());Objects.requireNonNull(orderUpdateParam.getName());
}
原理很简单,我们看下源码;
public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException();return obj;
}
4.2.3 使用 commons 包
我们可以使用 commons-lang3 或者 commons-collections4 等常用的工具类辅助我们判空。
4.2.3.1 使用字符串工具类:org.apache.commons.lang3.StringUtils
public void doSomething(String param) {if (StringUtils.isNotEmpty(param)) {// 使用param参数}
}
4.2.3.2 使用校验工具类:org.apache.commons.lang3.Validate
public static void doSomething(Object param) {Validate.notNull(param,"param must not null");
}
public static void doSomething2(List<String> parms) {Validate.notEmpty(parms);
}
该校验工具类支持多种类型的校验,支持自定义提示文本等。
前面已经介绍了读源码是最好的学习方式之一,这里我们看下底层的源码:
public static <T extends Collection<?>> T notEmpty(final T collection, final String message, final Object... values) {if (collection == null) {throw new NullPointerException(String.format(message, values));}if (collection.isEmpty()) {throw new IllegalArgumentException(String.format(message, values));}return collection;
}
该如果集合对象为 null 则会抛空 NullPointerException 如果集合为空则抛出 IllegalArgumentException。
通过源码我们还可以了解到更多的校验函数。
4.2.4 使用集合工具类:org.apache.commons.collections4.CollectionUtils
public void doSomething(List<String> params) {if (CollectionUtils.isNotEmpty(params)) {// 使用params}
}
4.2.5 使用 guava 包
可以使用 guava 包的 com.google.common.base.Preconditions 前置条件检测类。
同样看源码,源码给出了一个范例。原始代码如下:
public static double sqrt(double value) {if (value < 0) {throw new IllegalArgumentException("input is negative: " + value);}// calculate square root
}
使用 Preconditions 后,代码可以简化为:
public static double sqrt(double value) {checkArgument(value >= 0, "input is negative: %s", value);// calculate square root}
Spring 源码里很多地方可以找到类似的用法,下面是其中一个例子:
org.springframework.context.annotation.AnnotationConfigApplicationContext#register
public void register(Class<?>... annotatedClasses) {Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");this.reader.register(annotatedClasses);
}
org.springframework.util.Assert#notEmpty(java.lang.Object[], java.lang.String)
public static void notEmpty(Object[] array, String message) {if (ObjectUtils.isEmpty(array)) {throw new IllegalArgumentException(message);}
}
虽然使用的具体工具类不一样,核心的思想都是一致的。
4.2.6 自动化 API
4.2.6.1 使用 lombok 的 @Nonnull 注解
public void doSomething5(@NonNull String param) {// 使用paramproccess(param);}
查看编译后的代码:
public void doSomething5(@NonNull String param) {if (param == null) {throw new NullPointerException("param is marked non-null but is null");} else {this.proccess(param);}}
4.2.6.2 使用 IntelliJ IDEA 提供的 @NotNull 和 @Nullable 注解
maven 依赖如下:
<!-- https://mvnrepository.com/artifact/org.jetbrains/annotations -->
<dependency><groupId>org.jetbrains</groupId><artifactId>annotations</artifactId><version>17.0.0</version>
</dependency>
@NotNull 在参数上的用法和上面的例子非常相似。
public static void doSomething(@NotNull String param) {// 使用paramproccess(param);
}
我们可以去该注解的源码 org.jetbrains.annotations.NotNull#exception 里查看更多细节,大家也可以使用 IDEA 插件或者前面介绍的 JD-GUI 来查看编译后的 class 文件,去了解 @NotNull 注解的作用。
5. 总结
本节主要讲述空指针的含义,空指针常见的中枪姿势,以及如何避免空指针异常。下一节将为你揭秘 当 switch 遇到空指针,又会发生什么奇妙的事情。
相关文章:
开发中造成空指针的常见用法,如何避免
1. 前言 《手册》的第 7 页和 25 页有两段关于空指针的描述: 【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。 【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景: 返回类型为…...
MySQL事务和索引
目录 事务的概念 事务的四大特性(ACID) 原子性 隔离性 持久性 一致性 什么是脏读、幻读和不可重复读? 脏读 幻读 不可重复读 事务的隔离级别 读未提交 读已提交 可重复读 串行化 索引 索引优点 索引缺点 索引分类 索引设…...
Kali工具集简介
Kali Linux提供了数种经过定制的专门为渗透测试设计的工具。工具都会按下图中下拉选单所示的方式按组分类聚合。了解工具是做渗透测试第一个认知。 口Information Gathering(信息收集) 这些都是侦察工具,用来收集目标网络和设备的数据。在这类工具中,从找出设备的工具到查看使…...
离散数学 | 图论 | 欧拉图 | 哈密顿图 | 割点 | 桥(欧拉图和哈密顿图有没有割点和桥?)
本文主要解决以下几个问题: 1.欧拉图能不能有割点,能不能有桥? 2.哈密顿图能不能有割点,能不能有桥? 首先我们要明白几个定义 割点的定义就是在一个图G中,它本来是连通的,去掉一个点v以后这个…...
Android生命周期:理解与应用
摘要:Android生命周期是开发Android应用程序时至关重要的概念。本文将介绍Android生命周期的概念、生命周期方法的执行顺序以及如何在应用程序中正确地管理生命周期。我们还将讨论生命周期对于应用程序的重要性,并提供一些实际应用中的最佳实践和注意事项…...
00后真的是内卷王中王,真的想离职了....
都说00后躺平了,但是有一说一,该卷的还是卷。这不,前段时间我们公司来了个00年的,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。…...
linux Fd以及重定向讲解
感谢你的阅读,是对我最大的鼓励!!!! 目录 fd理解 文件操作重定向 让我们回顾C语言文件操作 首选我们要知道2个知识点: 额外知识点 如何理解一切皆文件呢? 当父进程fork创建子进程是否创建…...
Moonbeam近日提案公投一览
正在跟进Moonbeam治理的小伙伴,一起来快速浏览一下近期生态中正在发生的事情吧!其中包含多个去中心化应用的Grant加速计划提案、HRMP开拓提案以及优化质押相关平台的内容。许多提案都与网络的运作息息相关,一起了解和参与Moonbeam的发展吧&am…...
凝聚青年力量,打造数字化人才队伍
当代青年人勇于探索、敢于创新、勤于变革,积极承担社会责任。这与ABeam倡导的「Build Beyond As One.™」的品牌理念不谋而合。ABeam的青年员工是未来社会的中坚力量,也正用他们的青春能量助力ABeam在中国的发展。 01 新兴青年力量 对ABeam而言&#…...
蓝牙资讯|智能家居标准Matter 1.1 发布,智能家居产品兼容更丰富
据“CSA 连接标准联盟”官方微信号,Matter 1.1 版本已发布,“1.1 版本带来的更新使设备制造商和开发者上手更容易、产品获取认证更方便,也让产品能更快地交付给用户。该版本还为电池供电设备提供了更大支持,而这类设备涉及多种类型…...
Cube Map 系列之:手把手教你 实现天空盒(Sky Box)
什么是天空盒 An skybox is a box with textures on it to look like the sky in all directions or rather to look like what is very far away including the horizon.天空盒是一个使用纹理贴图构建的盒子,人在其中朝任何一个方向看去,其纹理彷佛天空…...
腾讯VS百度:在AI上下大赌注
来源:猛兽财经 作者:猛兽财经 腾讯控股(00700)最近已经把基础模型和生成式人工智能应用方面的行业突破视为其业务的新增长机会了,并且正在大力投资人工智能,从而增强其现有产品的竞争力和拓展新的机会,比如腾讯已经把…...
字节原来这么容易进,是面试官放水,还是公司实在是太缺人?
本人211非科班,之前在字节和腾讯实习过,这次其实没抱着什么特别大的希望投递,没想到字节可以再给我一次机会,还是挺开心的。 本来以为有个机会就不错啦!没想到能成功上岸,在这里要特别感谢帮我内推的同学&…...
生死疲劳|因为此书莫言获得诺贝尔奖
📚书名:《生死疲劳》 ✏️作者:莫言 历经六世的生死轮回, 三代人无尽的生死疲劳; 触碰极致的痛苦与快乐, 感受不灭的热情与希望。 🔥虽然本书长达39万字,但阅读过程却是无比的酣畅…...
Linux系统编程总结
day2 vim的三种工作模式 命令模式 vi hello.c zz 保存退出 2.编辑模式 i a o s (有大写)可以写东西 3.末行模式: 文本和末行模式不能直接切换 要切换回命令模式 再到末行模式,w:保存 q:退出 按两次esc回到命令模式 vim的基本…...
javascript基础二:Javscript字符串的常用方法有哪些?
在日常开发中,我们对字符串也是操作蛮多,这里我们来整理下字符串的一下最常用的方法 一、操作方法 字符串常用的操作方法归纳为增、删、改、查 增 这里增的意思并不是说直接增添内容,而是创建字符串的一个副本,再进行操作 除了…...
面了个 Java 实习生,小伙很优秀!
大家好,我是鱼皮,前几天给自己的公司面试了一位 Java 暑期实习生,候选人目前是大三。 整个过程我都录屏了,并且在征得候选人的同意后,把面试过程分享出来。一方面是希望对其他在学编程找工作的小伙伴有一些启发和参考…...
Java -并发(多线程)-Interview面试题收集
1、多线程并发 1)多线程中 synchronized 锁升级的原理是什么? synchronized 锁升级原理:在锁对象的对象头里面有一个 threadid 字段,在第一次访问的时候 threadid 为空,jvm 让其持有偏向锁,并将 threadid…...
HashMap的merge()方法
最近遇到一个需求,需要统计各个会员的正在履行合同的合同租金总计,以此作为制定会员等级的标准。但是之前这个方法其实是有的,只是写的乱七八糟,具体的代码就不太方便放上来,就说说大致的代码思路吧。 原代码思路是先查…...
用 mysql_secure_installation 工具来进行密码重置操作(有效)
mysql_secure_installation 工具用于在 MariaDB 中进行一些安全设置,包括重置 root 用户的密码。您可以按照以下步骤使用该工具来重置 root 用户的密码: 1. 以管理员身份登录到您的系统。 2. 执行以下命令以运行 mysql_secure_installation 工具&#…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
ArcGIS Pro制作水平横向图例+多级标注
今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作:ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等(ArcGIS出图图例8大技巧),那这次我们看看ArcGIS Pro如何更加快捷的操作。…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...
