Java-空链处理

什么是 null

在 Java 中,null 是一个非常常见的关键字,用于表示“没有值”或“空”。然而,对于初学者来说,null 的本质可能会感到有些困惑。在本文中,我们将详细探讨 null 在 Java 中的含义和使用。

在 Java 中,null 表示“没有值”或“空”。它是一个关键字,用于表示一个对象变量不引用任何对象。这意味着该变量没有指向任何有效的内存地址,因此它不指向任何对象。如果尝试在 null 引用上调用任何方法或字段,则会引发 NullPointerException 异常。

以下是一个示例:

String str = null;
int length = str.length(); // This will cause a NullPointerException

在这个例子中,str 被赋值为 null,因此它不引用任何有效的字符串对象。当试图调用 str.length() 时,将抛出 NullPointerException 异常。

在 Java 中,null 有许多用途。以下是一些常见的用途:

  1. 初始化对象引用 String str; // str is initialized tonull
  2. 表示无效的值 Person person1= new Person(“Alice”, null);
  3. 释放内存, 如果将一个对象变量设置为 null,它将不再引用该对象,并且该对象将变为不可访问。这意味着它可以被垃圾收集器回收,释放内存。

null的来源

Null 的产生是由于 1965 年的一个偶然事件。

托尼·霍尔(Tony Hoare)是快速排序算法的创造者,也是图灵奖(计算机领域的诺贝尔奖)的获得者。他把 Null 添加到了 ALGOL 语言中,因为它看起来很实用而且容易实现。但几十年后,他后悔了。Tony 表示,1965 年把 Null 引用加进 ALGOL W 时的想法非常简单,“就是因为这很容易实现。”但如今再次谈到当初的决定时,他表示这是个价值十亿美元的大麻烦:

“我称之为我的十亿美元错误……当时,我正在设计第一个全面的类型系统,用于面向对象语言的引用。我的目标是确保所有对引用的使用都是绝对安全的,由编译器自动执行检查。但是我无法拒绝定义一个 Null 引用的诱惑,因为它实在太容易实现了。这导致了无法计数的错误、漏洞和系统崩溃。在过去的四十年里,这些问题可能已经造成了十亿美元的损失。”

“NULL”:计算机科学中的最严重错误,造成十亿美元损失 - 计算机 - 软件编程 - 深度开源

搞笑的问题

桌子上有空杯子:杯子里有 0 mL水

桌子上没有杯子:杯子里有 null mL水

往空杯子里倒入一些水:杯子里有 114 mL水

往没有杯子的桌子上倒入等量水:你妈看见桌子上地上都是水拿出铜头皮带把你抽得如键山雏一般旋转。

北纬51度,东经0度:伦敦

北纬51度,东经null度:幻想乡

上午8点0分:周末这个点我表姐极有可能在赖床

上午8点null分:表坏了

往一张有0元的银行卡里转50块钱:卡的主人会拿着卡去吃疯狂星期四

往一张有null元的银行卡里转50块钱:这张卡不存在

计算 5-0 :5

计算 5-null :程序错误

我给你解释下为什么null有问题。

房间的左边有一堆苹果,小明吃光了。

房间的右边有一堆橘子,小红吃光了。

这时候,小刚进了屋,别人问他,这两堆东西是个什么情况……

小刚一脸蒙蔽:啊?两堆?你在说啥?

0说:“身是菩提树,心如明镜台,时时勤拂拭,勿使惹尘埃。”

null说:“菩提本无树,明镜亦非台,本来无一物,何处惹尘埃。”

null和0就不是一个境界

已知空解决方案

对于null,大家普遍都拿他当作“没有”的表示方式。比如getUser(userId)函数返回null,表示“找不到这个userId对应的user”。你可以强调说应该抛异常,或者使用Optional,或者以其他的形式表达“没有”,但是现实就是,使用null表示“没有”已经成为了某种“共识”。

而一旦一个东西没有,对其进行某个操作就是未定义的。例如getUser(userId).name可能就会NPE,因为user没有的情况下,获取其name也就没有意义。程序不会晓得没有user的情况下name应该怎么处理。如果不写代码特殊照顾,程序就只能傻乎乎的抛NPE等价的错误。于是这就需要程序员必须不断的做NPE检查。而人做这种工作,在没有其他支持下,有遗漏是必然的。某些遗漏造成的NPE会带来灾难性的结果。你能想象一个做手术的机器人程序,或者飞机飞控程序出现一个NPE是什么结果吗?

对于NPE有这么几种方案

1)完全不接受null。但“没有”这个概念得另外想办法。比如每个字段foo,都得弄一个对应的hasFoo的字段表示。取值也总得弄两次。但这样作和上面的问题是等价的,会遗漏if (foo != null)的程序员肯定也会遗漏if (hasFoo)。要不就把foo和hasFoo外边套一层,逼着程序员用getOrElse这样的方式做NPE检查。Option这类方案就是如此。

2)允许null,但是控制null的范围。假设程序在对外接触的界面上(比如接口的controller,访问DB时)进行判空,处理所有“没有”的情况。然后处理干净后对内部的程序总是not null的,不用管“没有”。编译器就负责保证那些not null的部分肯定不出问题。kotlin是这么干的。

3)允许null,通过与语法糖的形式让每次有null时的处理写的方便点。比如js里你可以这样写“(getUser(userId) || {}).name”或者“_.get(getUser(userId), ‘name’)”,这样用户找不到,至少能得到一个undefined的name,而不会NPE。简短的语法糖可以提高开发者做处理的概率。上面的这段代码如果用java就得写几行,程序员也许会更倾向于漏掉。

至于除0造成的问题,相对于null会少一些。只有遇到除0才会有问题。我所在领域见过的大多数程序根本不会做除法。但如果是数据分析等领域的,除0问题也会像null问题一样恶心。你总是要定义数据除0表达什么意思。也许就是一个错误需要报,也许是有实际含义的(比如垂直的斜率),你需要换一个方式表达它。

null 在 Java 的问题

以下是一些常见的问题:

1. 可能引发 NullPointerException

如果尝试在 null 引用上调用任何方法或字段,则会引发 NullPointerException 异常。这可以在编译时很难发现,因此需要小心处理 null 引用。

2. 可能导致代码复杂性

在使用 null 时,可能需要添加一些额外的逻辑来检查是否为空。这可能会使代码变得更加复杂,并增加错误的机会。

3. 可能会导致歧义

有时 null 可以引起歧义。例如,如果将一个方法的返回值设置为 null,则无法确定返回的值是否表示“未找到”或“出错”等意义。这可能导致代码更加难以维护和理解。

总结:

null 是 Java 中的一个关键字,表示“没有值”或“空”。它用于表示对象变量不引用任何对象,并且在某些情况下可以表示无效或缺失的值。在使用 null 时,需要小心处理可能引发 NullPointerException 和增加代码复杂性的问题。在确定使用 null 时,应该考虑使用其他替代方案,例如 Optional 类型和默认值。

如果经常使用Optional 的会发现, 很痛苦,为什么会这么说呢? 主要是抉择问题和Optional 不能够完全代替 if , 因为Optional 同一时间只能处理一个值的判空, 而遇到多值判空或者链路判空, 那么就会显得非常啰嗦而且麻烦还不如直接使用 if 来的实在,下面我针对上问题提出的一个解决方案就是链式判空处理。

为什么需要空链处理?

我们经常会处理,A-》B-》C-》D 这种对象链路, 转换为 java 代码如下:

if(a!=null&&a.getB()!=null&&a.getB().getC()!=null&&a.getB().getC().getD()!=null){}

如果我想在 C 不是空的时候处理点东西,然后在获取 D 代码如下:

if(a!=null&&a.getB()!=null&&a.getB().getC()!=null){///a.getB().getC() xxxxxx处理逻辑if(a.getB().getC().getD()!=null){}
}

还有一种情况就是一个对象中有多个字段需要进行判空处理, 这种场景是非常常见的也是非常容易出错的, 容易忘记判空或者自信觉得没有空。

if(a.getName()!=null){//xxxxx
}
if(a.getAddr()!=null){//xxxxx
}
if(a.getAddr()!=null&&a.getName()&&.....){//xxxxx
}
//.........................

以上举例只是生活中开发代码的一小部分, 实际业务稍微复杂点的场景, 是要比这个复杂 N 倍的 ,如何能搞高效的处理判空和避免发生NullPointerException 问题呢? 往下接着看。

最新版安装

settings.xml

<servers><server><id>java-huanmin-utils</id><username>60df3fd26da2f73831f05bfa</username><password>RXP3_Dmx[=gX</password></server>
</servers><repositories><repository><id>java-huanmin-utils</id><url>https://packages.aliyun.com/60df3fde4690c27532d3dd6c/maven/java-huanmin-utils</url><releases><enabled>true</enabled></releases><snapshots><enabled>true</enabled></snapshots></repository>
</repositories>

配置参考

settings_aly.xml

maven

<dependency><groupId>com.gitee.huanminabc</groupId><artifactId>null-chain</artifactId><version>1.0.7-RELEASE</version>
</dependency>

使用教程

概念(必读)

在null-chain 工具中主要思想就是让程序以任务的维度按照工厂流水线模式进行处理, 一旦某个任务是空的那么就不继续往下执行了 , 在代码编程的世界中 <font style="color:#DF2A3F;">可读性远比性能重要</font>

在空链处理中主要概念为:

  1. 开始
  2. 过程
  3. 转换
  4. 终结

注意: 开始 是必须的, 2,3,4 可以自己任意组合进行操作, 想要获取值,必须使用终结方法。

作为空链处理的实体类(强制要求):

  1. 类中必须实现 get/set 方法 (强制必须实现)
  2. 类中全部字段必须使用 **强制**必须使用包装类型
  3. 类中必须实现空构造方法
  4. 一个lombok 注解 <font style="color:#080808;background-color:#ffffff;">@Data</font> 可以搞定大部分要求。

报错符号:

链式处理最麻烦的就是一旦出问题非常难以定位到位置, 在空链中为了避免这个问题在设计之初就考虑到了。

在空链路符号就两种:

  • -> 表示正常
  • ? 表示这个节点是空的

下面是报错效果:

报错信息主要包括: 代码位置和具体哪个链路环节是空的或者问题, 大大的节约的排查问题的成本。

核心对象:

  • NULL(所有任务的开端,最常用的类)
  • NullChain(同步处理, 链式判空类)
  • NullChainAsync(异步处理, 链式判空类)

起始方法常用方法(NULL):

  • of (遇空不异常,后续任务不执行)
  • ofs (各种数组相关的对象转化为空链)
  • ofMap (对象和 map 转化为空链)
  • ofMerge (将多个空链对象合并为一个空连, 适用于对多个不同类型对象内部的值合并到一个对象中, do->dto->vo)

过程常用方法(NullChain****):

  • of (遇空不异常,后续任务不执行)
  • peek (不改变对象类型,提前偷看内容,然后修改对象内容,影响后续任务)
  • map(将一个类型转换另一个类型, 也可以说将 a 映射为 b, 常用于 bo->dto->vo )
  • or(如果上一个任务为空,那么就执行supplier 来换一个任务,如果不为空那么就返回当前任务)
  • pick(将对象内的多个字段提取出来转换为新的对象, 常用于 bo->dto->vo , 和 map 不一样的是通过 lmabda 方式, 使用起来更加简洁 )
  • copy 浅拷贝
  • deepCopy 深度拷贝

转换常用方法(NullConvert):

  • str (如果值是字符串类型,那么可以通过此方法获取不为空的字符串, 包括长度不能小于 0)
  • integer (如果是字符串或者数值类型的, 可以通过此方法将值转换为数字)
  • dateFormat(将时间类型(Date,LocalDate,LocalDateTime), 10或13位时间戳(数值或字符串), 转换为指定格式化后的时间字符串)
  • json(将对象转换为json , )
  • bytes(序列化) 反序列化需要使用 NULL.toNULL(byte[] bytes, Class<T> tClass) 方法
  • async (将代码以异步的方式运行, 下一个任务会等到上一个任务结束才执行, 并且可接收上一个任务的返回值) 支持自定义线程池

终结常用方法:(NullFinality)

  • is 和 iss 判断是否是空(true 是空, false 不是空)
  • get(取值, 如果有空就异常, 并且打印具体异常的位置)
  • ifPresent (如果上一个任务不是空那么就执行action,否则不执行)
  • orThrow(如果是空那么自定义抛出异常)
  • orElse(如果是空那么给默认值)
  • stream 和 parallelStream (直接将空链无缝衔接流, 后期会自己重写流不然入参还需要指定类型)
  • forEach (兼容集合,数组和 map )

性能: 单线程 10万次循环链路处理, 高配电脑测试基本都在 20~50 毫秒左右, 如果电脑差点也是在 100~200 毫秒左右,这还是算上了初始化和循环的时间, 实际代码运行后执行效率会比这个要高很多的。

    @Testpublic void time() throws Exception {CodeTimeUtil.creator(()->{for (int i = 0; i < 100000; i++) {NULL.of(userEntity).of(UserEntity::getRoleData).of(RoleEntity::getRoleDescription).get();}});}

:::color4
测试实体

:::

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserEntity implements Serializable {private static final long serialVersionUID = 1L;private Integer id;private String name; //名称private String pass; //密码private Integer age; //年龄private String sex;//性别private String site; //地址private Boolean del; //是否删除@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date date; //日期private RoleEntity roleData;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RoleEntity implements Serializable {private static final long serialVersionUID = 1L;private long id;private String  roleName;// 防止 JSON parse error: Cannot deserialize value of type `java.util.Date` from String 错误@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date    roleCreationTime;private String  roleDescription;private boolean roleStatus;
}

初始化值

    UserEntity userEntity = new UserEntity();@Beforepublic void before() {userEntity.setId(1);userEntity.setName("huanmin");userEntity.setAge(33);userEntity.setDate(new Date());RoleEntity roleEntity = new RoleEntity();roleEntity.setRoleName("admin");roleEntity.setRoleDescription("123");userEntity.setRoleData(roleEntity);}

判空

在链路中间处理,然后经过各种转化,发现是空的然后报错了

String roleName = NULL.of(userEntity).peek((data) -> {data.getRoleData().setRoleName(null);return data;
}).of(UserEntity::getRoleData).map(UserEntity::getRoleData).of(RoleEntity::getRoleName).map(RoleEntity::getRoleName).get();
System.out.println(roleName);//error

如果不想报错那么可以给一个默认值

String roleName = NULL.of(userEntity).peek((data) -> {data.getRoleData().setRoleName(null);return data;
}).of(UserEntity::getRoleData).map(UserEntity::getRoleData).of(RoleEntity::getRoleName).map(RoleEntity::getRoleName).orElse("default");
System.out.println(roleName);//default

a 转 b 转换为 b 对象, 拿 b 对象的值, 如果有空抛出自定义异常

userEntity.getRoleData().setRoleName(null);
String s2 = NULL.of(userEntity).map(UserEntity::getRoleData).map(RoleEntity::getRoleName).orThrow(RuntimeException::new);
System.out.println(s2);

还有很多用法就自己探索把…

转换

转换的意思很简单就是将类型转换,或者将 a 对象转换为 b 对象…

将字符串转换为数值

Integer convert = NULL.of(userEntity).map(UserEntity::getRoleData).map(RoleEntity::getRoleDescription).map(Integer::parseInt).get();
System.out.println(convert);
Integer anInt = NULL.of(userEntity).map(UserEntity::getRoleData).map(RoleEntity::getRoleDescription).integer().get();
System.out.println(anInt);

将一个对象映射为另一个对象

UserData userData1 = NULL.of(userEntity).of(UserEntity::getRoleData).map((data) -> {UserData userData = new UserData();userData.setName("name");userData.setSex("1");return userData;
}).get();
System.out.println(userData1);

将 a 转化为 b 然后提取 b 部分值返回新的对象

RoleEntity roleEntity = NULL.of(userEntity).map(UserEntity::getRoleData).pick(RoleEntity::getRoleName, RoleEntity::getRoleDescription).get();
System.out.println(roleEntity);

将对象转换为 json

String json = NULL.of(userEntity).map(UserEntity::getRoleData).json().get();
System.out.println(json);

对时间进行格式

String dateFormat = NULL.of(userEntity).map(UserEntity::getRoleData).map(RoleEntity::getRoleCreationTime).dateFormat(DateEnum.DATETIME_PATTERN).get();
System.out.println(dateFormat);

还有很多用法就自己探索把…

终结

准确来说能拿到结果的都算是终结方法, 在上面我们已经演示了 get 方法这就是终结方法。 这里就不在演示使用了自习查看NullFinality类, 上面已经演示了这么多的案例了。

NULL.of(null,false).ifPresent(System.out::println);//false
NULL.of("  ","123").ifPresent(System.out::println); //123

异步编排

在空链中提供了一个非常好用的链式异步编排,拥有和同步一样的功能。,需要通过async 将当前处理流转换为异步处理流。当然也可以转换回去sync

异步处理

    @Testpublic  void test1(){NULL.of(userEntity).of(UserEntity::getRoleData).async().map(RoleEntity::getRoleName).get((data)->{System.out.println(data);SleepTools.second(2);});System.out.println("====");}

异步转同步

//不推荐这样一条龙进行异步转同步, 因为这样意义不大(和同步没啥区别都,都阻塞在这一行了, 异步链路的前一个没处理完毕后面的会等待前一个结果)
NULL.of(userEntity).map(UserEntity::getRoleData).async().map(RoleEntity::getRoleName).get((data) -> {System.out.println(data);SleepTools.second(2);
});System.out.println("====");
userEntity.getRoleData().setRoleName(null);//推荐这样的写法, 先异步各种处理,  让代码脱离主线程,  之后我们可以写自己的逻辑,    然后再同步获取结果
NullChainAsync<String> map = NULL.of(userEntity).async().map(UserEntity::getRoleData).map(RoleEntity::getRoleName);
//执行其他逻辑代码
//xxxxx//获取之前异步的结果
try {String res = map.get();System.out.println(res);
} catch (NullChainCheckException e) {log.error("空值error",e);
}

自定义线程池 (如果不是 cpu 密集的任务长时间占用线程, 一般用默认的线程池就足够了)

ThreadFactoryUtil.addExecutor("test1",10,100); //建议在项目启动的时候配置, 不要放到业务代码里面,  这个key可以做一个枚举统一管理
//指定使用的线程池key
NULL.of(userEntity).map(UserEntity::getRoleData).async("test1").map(RoleEntity::getRoleName).ifPresent((data) -> {System.out.println(data);SleepTools.second(2);
});

继承扩展

让一个实体类继承NULLExt,就能直接调用空链处理, 需要保证最开头的实体类变量不能是空的 , 如果不能保证还是老老实实的使用 NULL.of

@Builder
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserExtEntity  implements Serializable, NULLExt<UserExtEntity> {
UserExtEntity userExtEntity = new UserExtEntity();
userExtEntity.setId(1);
//userExtEntity 不能是空的
Integer i = userExtEntity.map(UserExtEntity::getId).get();
System.out.println(i);

提示: 一般来说 web接口 的入参 和 prc 接口 的对象入参基本不可能是 null 这种情况是可以直接使用 继承扩展的

集合 , Stream , Map

遍历
  1. 集合相关的比如 List Set Queue 等 都必须使用 <font style="color:#080808;background-color:#ffffff;">NULL.ofCollection</font>起手或者继承 <font style="color:#080808;background-color:#ffffff;">NULLExt</font>
  2. Map 相关的比如 HashMap LinkedHashMap 等 都必须使用 <font style="color:#080808;background-color:#ffffff;">NULL.ofKV</font> 起手或者继承 <font style="color:#080808;background-color:#ffffff;">NULLExt</font>
List<String> list= Arrays.asList("1","2","3");
//list=null;
NULL.ofCollection(list).stream().forEach((data) -> {System.out.println(data);
});NULL.ofCollection(userEntityList).stream().forEach((data) -> {System.out.println(data);
});String a="1";
NULL.of(a).stream().forEach(System.out::println);//直接遍历list
NULL.ofCollection(list).forEach(System.out::println);
Map<String, String> stringStringMap = new HashMap<String, String>() {{put("1", "1");put("2", "2");put("3", "3");
}};//转流遍历map
NULL.ofKV(stringStringMap).stream().map((node) -> node.getKey() + "__" + node.getValue()).forEach(System.out::println);//直接遍历map
NULL.ofKV(stringStringMap).forEach((node) -> {System.out.println(node.getKey() + "__" + node.getValue());
});
操作

增删改在在大部分情况下都是安全的不会出现空的情况, 所以我们只针对各种查询做处理

Map<String, String> stringStringMap = new HashMap<String, String>() {{put("1", "1");put("2", "2");put("3", "3");
}};
boolean bool = NULL.ofKV(stringStringMap).isKey("1", "2");
System.out.println(bool); //falseNode<String, String> stringStringNode = NULL.ofKV(stringStringMap).map("1").orElse(Node.NEW("1", "1"));
System.out.println(stringStringNode);NULL.ofKV(stringStringMap).map("3").map(Node::getValue).ifPresent(System.out::println);ListTest<UserEntity> listTest = new ListTest<>();
listTest.add(userEntity);
NULL.ofCollection(listTest).map(0).ifPresent(System.out::println);UserEntity[] userEntities = new UserEntity[]{userEntity};
NULL.ofArray(userEntities).map(0).ifPresent(System.out::println);

其他工具

自行查看源码接口文件:

  1. NULL , NULLExt , NullChain , NullConvert , NullFinality , NullChainAsync 。。。。。。
  2. NULL 继承了 NullUtil 万能判空 NULL.non(accountFlowNew, query.getBelongingPartnerId())

最佳实践

无论是入参还是出参始终保持空链对象(支持 PRC) , 这样就能极大地减少空处理引发的问题

// 实践1
public NullChain<RoleEntity>  handle(NullChain<UserEntity> userEntityNullChain){RoleEntity roleEntity = NULL.of(userEntity).map(UserEntity::getRoleData).orElse(new RoleEntity());roleEntity.setId(1);//xxxxreturn NULL.of(roleEntity);
}// 实践2
public NullChain<String>  handle2() {//1. 不知道从哪里来的数据UserEntity userEntity = new UserEntity();NULL.of(userEntity).is(UserEntity::getId, UserEntity::getName);//2. 从数据库查询return NULL.of(userEntity).map2((chain,data) -> {if (chain.is(UserEntity::getId, UserEntity::getName, UserEntity::getDate)) {//xxxxxxx,取出数据经过处理return new RoleEntity();}//如果不满足条件,返回空return null;}).map(RoleEntity::getRoleName);
}
//拿到用户角色, 如果没有就默认admin
String roleName = getRoleName().orElse("admin");//实践3
private void pageBelongingPartnerIdHandle(AccountxxxQuery query) {//如果xxid不是空的那么就需要把相关xxx查询出来query.map(AccountxxxQuery::getBelongingPartnerId).map((belongingPartnerId) -> accountNewManager.queryAccountByBelongingPartnerId(belongingPartnerId, ProductEnum.LIJIANJIN)).ifPresent((accountOns) -> query.getAccountNos().addAll(accountOns));
}//实践4
public ResultX<AccountxxxDTO> getAccountLastFlow(AccountxxxQuery query) {NullChain<Accountxxx> accountxxxNullChain = accountxxxManager.queryxxxlowOne(query);if (query.non(AccountxxxQuery::getBelongingPartnerId)) {//判断是否存在xxid, 如果存在那么校验账户的xxxboolean notEq = accountxxxNullChain.map((data) -> accountNewManager.queryxxxxtNo(data.getAxxxNo())).map(AccountNew::getBelongingPartnerId).notEq(query.getBelongingPartnerId());if (notEq) {log.warn("getAccounxxx失败query:{}", query);return ResultX.success();}}return  accountxxxNullChain.map(accountxxxConverter::toDTO).map(ResultX::success).orElse(ResultX.success());
}

如果在 Controller 中返回值也想返回NullChain ,那么就需要在统一返回拦截的地方把空链里面的值取出来返回给前端

警告问题

vararg 形参的未检查的泛型数组创建, 可以在IDEA中给禁止了不然警告的烦人

支持

相关联系方式(添加烦请注明来意):

  • QQ:3426154361
  • 邮件:3426154361@qq.com

文章原文地址: https://www.yuque.com/huanmin-4bkaa/eeags4/by8xf3rw826bycso?singleDoc# 《Java-空链处理》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/61151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch使用教程-深度学习框架

PyTorch使用教程-深度学习框架 1. PyTorch简介 1.1-什么是PyTorch ​ PyTorch是一个广泛使用的开源机器学习框架&#xff0c;特别适合深度学习的应用。它以其动态计算图而闻名&#xff0c;允许在运行时修改模型&#xff0c;使得实验和调试更加灵活。PyTorch提供了强大的GPU加…

供应链管理、一件代发系统功能及源码分享 PHP+Mysql

随着电商行业的不断发展&#xff0c;传统的库存管理模式已经逐渐无法满足市场需求。越来越多的企业选择“一件代发”模式&#xff0c;即商家不需要自己储备商品库存&#xff0c;而是将订单直接转给供应商&#xff0c;由供应商直接进行发货。这种方式极大地降低了企业的运营成本…

Pr:音频过渡

Adobe Premiere Pro 自带一组共三个音频过渡 Audio Transitions效果。 对音频剪辑之间应用交叉淡化 Crossfade过渡&#xff0c;操作方式类似于应用视频过渡效果。 对于交叉淡化&#xff0c;要保证前剪辑的出点之后及后剪辑的入点之前有足够的预留内容&#xff08;也称“手柄”&…

前端页面开发步骤详解

目录 前言1. 页面搭建1.1 HTML 标签结构1.2 CSS 样式设计 2. 数据绑定与事件处理2.1 数据绑定2.2 表单校验 3. 调用后台接口3.1 接口文档与工具封装3.2 参数传递与接口调用 结语 前言 在前端开发过程中&#xff0c;从页面搭建到与后台接口对接是一个必不可少的完整流程。无论是…

A037-基于Spring Boot的二手物品交易的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

两行命令搭建深度学习环境(Docker/torch2.5.1+cu118/命令行美化+插件),含完整的 Docker 安装步骤

深度学习环境的配置过于繁琐&#xff0c;所以我制作了两个基础的镜像&#xff0c;希望可以帮助大家节省时间&#xff0c;你可以选择其中一种进行安装&#xff0c;版本说明&#xff1a; base 版本基于 pytorch/pytorch:2.5.1-cuda11.8-cudnn9-devel&#xff0c;默认 python 版本…

EXCEL延迟退休公式

如图&#xff1a; A B为手工输入 C2EOMONTH(A2,B2*12) D2EOMONTH(C2,IF(C2>DATEVALUE("2025-1-1"),INT((DATEDIF(DATEVALUE("2025-1-1"),C2,"m")4)/4),0)) E2EOMONTH(A2,B2*12IF(EOMONTH(A2,B2*12)>DATEVALUE("2025-1-1"),INT(…

区块链技术在数据安全中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 区块链技术在数据安全中的应用 区块链技术在数据安全中的应用 区块链技术在数据安全中的应用 引言 区块链技术基础 1.1 区块链的…

GIT 入门详解指南

前言&#xff1a; 注&#xff1a;本博客仅用于记录本人学习过程中对git的理解&#xff0c;仅供学习参考&#xff0c;如有异议请自行查资料求证 安装 使用git之前必须完成git的安装&#xff0c;Git 目前支持 Linux/Unix、Solaris、Mac和 Windows 平台上运行 git 安装教程 基本…

讯飞、阿里云、腾讯云:Android 语音合成服务对比选择

在 移动端 接入语音合成方面&#xff0c;讯飞和腾讯云等都是优秀的选择&#xff0c;但各有其特点和优势。咱们的需求是需要支持普通话/英语/法语三种语言&#xff0c;以下是对各个平台的详细比较&#xff1a; 一、讯飞语音合成介绍 与语音听写相反&#xff0c;语音合成是将一段…

HarmonyOS本地存储-Preferences(用户首选项)的使用

一&#xff0c;用户首选项简述 ohos.data.preferences (用户首选项) 用户首选项为应用提供Key-Value键值型的数据处理能力&#xff0c;支持应用持久化轻量级数据&#xff0c;并对其修改和查询。 数据存储形式为键值对&#xff0c;键的类型为字符串型&#xff0c;值的存储数据…

【机器学习】回归模型(线性回归+逻辑回归)原理详解

线性回归 Linear Regression 1 概述 线性回归类似高中的线性规划题目。线性回归要做的是就是找到一个数学公式能相对较完美地把所有自变量组合&#xff08;加减乘除&#xff09;起来&#xff0c;得到的结果和目标接近。 线性回归分为一元线性回归和多元线性回归。 2 一元线…

OceanBase 分区表详解

1、分区表的定义 在OceanBase数据库中&#xff0c;普通的表数据可以根据预设的规则被分割并存储到不同的数据区块中&#xff0c;同一区块的数据是在一个物理存储上。这样被分区块的表被称为分区表&#xff0c;而其中的每一个独立的数据区块则被称为一个分区。 如下图所示&…

【Android原生问题分析】夸克、抖音划动无响应问题【Android14】

1 问题描述 偶现问题&#xff0c;用户打开夸克、抖音后&#xff0c;在界面上划动无响应&#xff0c;但是没有ANR。回到Launcher后再次打开夸克/抖音&#xff0c;发现App的界面发生了变化&#xff0c;但是仍然是划不动的。 2 log初分析 复现问题附近的log为&#xff1a; 用户…

使用 K-means 算法进行豆瓣读书数据的文本聚类分析

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Django5 2024全栈开发指南(二):Django项目配置详解

目录 一、基本配置信息二、资源文件配置2.1 资源路由——STATIC_URL2.2 资源集合——STATICFILES_DIRS2.3 资源部署——STATIC_ROOT2.2.4 媒体资源——MEDIA 三、模板配置四、数据库配置4.1 mysqlclient连接MySQL4.2 pymysql连接MySQL4.3 多个数据库的连接方式4.4 使用配置文件…

数据结构-二叉搜索树(Java语言)

目录 1.概念 2.查找search 3.插入insert ​编辑4.删除remove&#xff08;难点&#xff09; 5.性能分析 1.概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树 : 1.若它的左子树不为空&#xff0c;则左子树上所有节点的值都…

学习笔记:黑马程序员JavaWeb开发教程(2024.11.18)

9.8 Mybatis-基础操作-查询&#xff08;条件查询&#xff09; 需要模糊查询&#xff0c;根据要求&#xff0c;我们需要在关键词前后都加上%&#xff0c;但是我们不能使用‘%#{内容}%’的形式&#xff0c;因为#{内容}最终会变成?&#xff0c;而?不能放在‘’之中&#xff…

数据分析-48-时间序列变点检测之在线实时数据的CPD

文章目录 1 时间序列结构1.1 变化点的定义1.2 结构变化的类型1.2.1 水平变化1.2.2 方差变化1.3 变点检测1.3.1 离线数据检测方法1.3.2 实时数据检测方法2 模拟数据2.1 模拟恒定方差数据2.2 模拟变化方差数据3 实时数据CPD3.1 SDAR学习算法3.2 Changefinder模块3.3 恒定方差CPD3…

学习大数据DAY61 宽表加工

目录 模型设计 加工宽表 任务调度&#xff1a; 大表 - 把很多数据整合起来 方便后续的明细查询和指标计算 模型设计 设计 建模 设计: excel 文档去编写 建模: 使用建模工具 PowerDesigner Navicat 在线画图工具... 把表结构给绘 制出来 共享\项目课工具\pd 加工宽表 数…