30个类手写Spring核心原理之自定义ORM(上)(6)

2024-01-25 16:20

本文主要是介绍30个类手写Spring核心原理之自定义ORM(上)(6),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文节选自《Spring 5核心原理》

1 实现思路概述

1.1 从ResultSet说起

说到ResultSet,有Java开发经验的“小伙伴”自然最熟悉不过了,不过我相信对于大多数人来说也算是“最熟悉的陌生人”。从ResultSet取值操作大家都会,比如:


private static List<Member> select(String sql) {List<Member> result = new ArrayList<>();Connection con = null;PreparedStatement pstm = null;ResultSet rs = null;try {//1. 加载驱动类Class.forName("com.mysql.jdbc.Driver");//2. 建立连接con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo", "root","123456");//3. 创建语句集pstm =  con.prepareStatement(sql);//4. 执行语句集rs = pstm.executeQuery();while (rs.next()){Member instance = new Member();instance.setId(rs.getLong("id"));instance.setName(rs.getString("name"));instance.setAge(rs.getInt("age"));instance.setAddr(rs.getString("addr"));result.add(instance);}//5. 获取结果集}catch (Exception e){e.printStackTrace();}//6. 关闭结果集、关闭语句集、关闭连接finally {try {rs.close();pstm.close();con.close();}catch (Exception e){e.printStackTrace();}}return result;
}

以上我们在没有使用框架以前的常规操作。随着业务和开发量的增加,在数据持久层这样的重复代码出现频次非常高。因此,我们就想到将非功能性代码和业务代码进行分离。我们首先想到将ResultSet封装数据的代码逻辑分离,增加一个mapperRow()方法,专门处理对结果的封装,代码如下:


private static List<Member> select(String sql) {List<Member> result = new ArrayList<>();Connection con = null;PreparedStatement pstm = null;ResultSet rs = null;try {//1. 加载驱动类Class.forName("com.mysql.jdbc.Driver");//2. 建立连接con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo", "root","123456");//3. 创建语句集pstm =  con.prepareStatement(sql);//4. 执行语句集rs = pstm.executeQuery();while (rs.next()){Member instance = mapperRow(rs,rs.getRow());result.add(instance);}//5. 获取结果集}catch (Exception e){e.printStackTrace();}//6. 关闭结果集、关闭语句集、关闭连接finally {try {rs.close();pstm.close();con.close();}catch (Exception e){e.printStackTrace();}}return result;
}private static Member mapperRow(ResultSet rs, int i) throws Exception {Member instance = new Member();instance.setId(rs.getLong("id"));instance.setName(rs.getString("name"));instance.setAge(rs.getInt("age"));instance.setAddr(rs.getString("addr"));return instance;
}

但在真实的业务场景中,这样的代码逻辑重复率实在太高,上面的改造只能应用Member类,换一个实体类又要重新封装,聪明的程序员肯定不会通过纯体力劳动给每一个实体类写一个mapperRow()方法,一定会想到代码复用方案。我们不妨来做这样一个改造。
先创建Member类:


package com.gupaoedu.vip.orm.demo.entity;import lombok.Data;import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;@Entity
@Table(name="t_member")
@Data
public class Member implements Serializable {@Id private Long id;private String name;private String addr;private Integer age;@Overridepublic String toString() {return "Member{" +"id=" + id +", name='" + name + '\'' +", addr='" + addr + '\'' +", age=" + age +'}';}
}

优化JDBC操作:


public static void main(String[] args) {Member condition = new Member();condition.setName("Tom");condition.setAge(19);List<?> result =  select(condition);System.out.println(Arrays.toString(result.toArray()));
}private static List<?> select(Object condition) {List<Object> result = new ArrayList<>();Class<?> entityClass = condition.getClass();Connection con = null;PreparedStatement pstm = null;ResultSet rs = null;try {//1. 加载驱动类Class.forName("com.mysql.jdbc.Driver");//2. 建立连接con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo? characterEncoding=UTF-8&rewriteBatchedStatements=true","root","123456");//根据类名找属性名Map<String,String> columnMapper = new HashMap<String,String>();//根据属性名找字段名Map<String,String> fieldMapper = new HashMap<String,String>();Field[] fields =  entityClass.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);String fieldName = field.getName();if(field.isAnnotationPresent(Column.class)){Column column = field.getAnnotation(Column.class);String columnName = column.name();columnMapper.put(columnName,fieldName);fieldMapper.put(fieldName,columnName);}else {//默认就是字段名、属性名一致columnMapper.put(fieldName, fieldName);fieldMapper.put(fieldName,fieldName);}}//3. 创建语句集Table table = entityClass.getAnnotation(Table.class);String sql = "select * from " + table.name();StringBuffer where = new StringBuffer(" where 1=1 ");for (Field field : fields) {Object value =field.get(condition);if(null != value){if(String.class == field.getType()) {where.append(" and " + fieldMapper.get(field.getName()) + " = '" + value + "'");}else{where.append(" and " + fieldMapper.get(field.getName()) + " = " + value + "");}//其他的在这里就不一一列举,后面我们手写ORM框架时会完善}}System.out.println(sql + where.toString());pstm =  con.prepareStatement(sql + where.toString());//4. 执行语句集rs = pstm.executeQuery();//元数据?//保存了处理真正数值以外的所有附加信息int columnCounts = rs.getMetaData().getColumnCount();while (rs.next()){Object instance = entityClass.newInstance();for (int i = 1; i <= columnCounts; i++) {//实体类属性名,对应数据库表的字段名//可以通过反射机制拿到实体类的所有字段//从rs中取得当前这个游标下的类名String columnName = rs.getMetaData().getColumnName(i);//有可能是私有的Field field = entityClass.getDeclaredField(columnMapper.get(columnName));field.setAccessible(true);field.set(instance,rs.getObject(columnName));}result.add(instance);}//5. 获取结果集}catch (Exception e){e.printStackTrace();}//6. 关闭结果集、关闭语句集、关闭连接finally {try {rs.close();pstm.close();con.close();}catch (Exception e){e.printStackTrace();}}return result;
}

上面巧妙地利用反射机制读取Class信息和Annotation信息,将数据库表中的列和类中的字段进行关联映射并赋值,以减少重复代码。

1.2 为什么需要ORM框架

通过前面的讲解,我们已经了解ORM框架的基本实现原理。ORM是指对象关系映射(Object Relation Mapping),映射的不只是对象值,还有对象与对象之间的关系,例如一对多、多对多、一对一这样的表关系。现在市面上ORM框架也非常多,有大家所熟知的Hibernate、Spring JDBC、MyBatis、JPA等。在这里做一个简单的总结,如下表所示。

名称特征描述
Hibernate全自动(挡)不需要写一句SQL
MyBatis半自动(挡)手自一体,支持简单的映射,复杂关系需要自己写SQL
Spring JDBC纯手动(挡)所有的SQL都要自己写,它帮我们设计了一套标准流程

既然市面上有这么多选择,我为什么还要自己写 ORM框架呢?
这得从我的一次空降担任架构师的经验说起。空降面临最大的难题就是如何取得团队“小伙伴们”的信任。当时,团队总共就8人,每个人的水平参差不齐,甚至有些人还没接触过MySQL,诸如Redis等缓存中间件更不用说了。基本只会使用Hibernate的CRUD,而且已经影响到了系统性能。由于工期紧张,没有时间和精力给团队做系统培训,也为了兼顾可控性,于是就产生了自研ORM框架的想法。我做了这样的顶层设计,以降低团队“小伙伴们”的存息成本,顶层接口统一参数、统一返回值,具体如下。

**(1)规定查询方法的接口模型为: **


/*** 获取列表* @param queryRule 查询条件* @return*/
List<T> select(QueryRule queryRule) throws Exception;/*** 获取分页结果* @param queryRule 查询条件* @param pageNo 页码* @param pageSize 每页条数* @return*/
Page<?> select(QueryRule queryRule,int pageNo,int pageSize) throws Exception;/*** 根据SQL获取列表* @param sql SQL语句* @param args 参数* @return*/
List<Map<String,Object>> selectBySql(String sql, Object... args) throws Exception;/*** 根据SQL获取分页* @param sql SQL语句* @param pageNo 页码* @param pageSize 每页条数* @return*/
Page<Map<String,Object>> selectBySqlToPage(String sql, Object [] param, int pageNo, int pageSize) throws Exception;

(2)规定删除方法的接口模型为:


/*** 删除一条记录* @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空不予执行* @return*/
boolean delete(T entity) throws Exception;/*** 批量删除* @param list* @return 返回受影响的行数* @throws Exception*/
int deleteAll(List<T> list) throws Exception;

(3)规定插入方法的接口模型为:


/*** 插入一条记录并返回插入后的ID* @param entity 只要entity不等于null,就执行插入* @return*/
PK insertAndReturnId(T entity) throws Exception;/*** 插入一条记录自增ID* @param entity* @return* @throws Exception*/
boolean insert(T entity) throws Exception;/*** 批量插入* @param list* @return 返回受影响的行数* @throws Exception*/
int insertAll(List<T> list) throws Exception;

(4)规定修改方法的接口模型为:


/***  修改一条记录* @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空不予执行* @return* @throws Exception*/
boolean update(T entity) throws Exception;

利用这套基础的API,后面我又基于Redis、MongoDB、ElasticSearch、Hive、HBase各封装了一套,以此来降低团队的学习成本,也大大提升了程序的可控性,更方便统一监控。

2 搭建基础架构

2.1 Page

定义Page类的主要目的是为后面的分页查询统一返回结果做顶层支持,其主要功能包括分页逻辑的封装、分页数据。


package javax.core.common;import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;/*** 分页对象,包含当前页数据及分页信息,如总记录数* 能够支持和JQuery EasyUI直接对接,能够支持和BootStrap Table直接对接*/
public class Page<T> implements Serializable {private static final long serialVersionUID = 1L;private static final int DEFAULT_PAGE_SIZE = 20;private int pageSize = DEFAULT_PAGE_SIZE; //每页的记录数private long start; //当前页第一条数据在List中的位置,从0开始private List<T> rows; //当前页中存放的记录,类型一般为Listprivate long total; //总记录数/*** 构造方法,只构造空页*/public Page() {this(0, 0, DEFAULT_PAGE_SIZE, new ArrayList<T>());}/*** 默认构造方法* * @param start 本页数据在数据库中的起始位置* @param totalSize 数据库中总记录条数* @param pageSize 本页容量* @param rows 本页包含的数据*/public Page(long start, long totalSize, int pageSize, List<T> rows) {this.pageSize = pageSize;this.start = start;this.total = totalSize;this.rows = rows;}/*** 取总记录数*/public long getTotal() {return this.total;}public void setTotal(long total) {this.total = total;}/*** 取总页数*/public long getTotalPageCount() {if (total % pageSize == 0){return total / pageSize;}else{return total / pageSize + 1;}}/*** 取每页数据容量*/public int getPageSize() {return pageSize;}/*** 取当前页中的记录*/public List<T> getRows() {return rows;}public void setRows(List<T> rows) {this.rows = rows;}/*** 取该页的当前页码,页码从1开始*/public long getPageNo() {return start / pageSize + 1;}/*** 该页是否有下一页*/public boolean hasNextPage() {return this.getPageNo() < this.getTotalPageCount() - 1;}/*** 该页是否有上一页*/public boolean hasPreviousPage() {return this.getPageNo() > 1;}/*** 获取任意一页第一条数据在数据集中的位置,每页条数使用默认值* * @see #getStartOfPage(int,int)*/protected static int getStartOfPage(int pageNo) {return getStartOfPage(pageNo, DEFAULT_PAGE_SIZE);}/*** 获取任意一页第一条数据在数据集中的位置* * @param pageNo 从1开始的页号* @param pageSize 每页记录条数* @return 该页第一条数据*/public static int getStartOfPage(int pageNo, int pageSize) {return (pageNo - 1) * pageSize;}}

2.2 ResultMsg

ResultMsg类主要是为统一返回结果做的顶层设计,主要包括状态码、结果说明内容和返回数据。


package javax.core.common;import java.io.Serializable;//底层设计
public class ResultMsg<T> implements Serializable {private static final long serialVersionUID = 2635002588308355785L;private int status; //状态码,系统的返回码private String msg;  //状态码的解释private T data;  //放任意结果public ResultMsg() {}public ResultMsg(int status) {this.status = status;}public ResultMsg(int status, String msg) {this.status = status;this.msg = msg;}public ResultMsg(int status, T data) {this.status = status;this.data = data;}public ResultMsg(int status, String msg, T data) {this.status = status;this.msg = msg;this.data = data;}public int getStatus() {return status;}public void setStatus(int status) {this.status = status;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}}

2.3 BaseDao

作为所有BaseDao持久化框架的顶层接口,主要定义增、删、改、查统一的参数列表和返回值。


package javax.core.common.jdbc;import com.gupaoedu.vip.orm.framework.QueryRule;import javax.core.common.Page;
import java.util.List;
import java.util.Map;public interface BaseDao<T,PK> {/*** 获取列表* @param queryRule 查询条件* @return*/List<T> select(QueryRule queryRule) throws Exception;/*** 获取分页结果* @param queryRule 查询条件* @param pageNo 页码* @param pageSize 每页条数* @return*/Page<?> select(QueryRule queryRule,int pageNo,int pageSize) throws Exception;/*** 根据SQL获取列表* @param sql SQL语句* @param args 参数* @return*/List<Map<String,Object>> selectBySql(String sql, Object... args) throws Exception;/*** 根据SQL获取分页* @param sql SQL语句* @param pageNo 页码* @param pageSize 每页条数* @return*/Page<Map<String,Object>> selectBySqlToPage(String sql, Object [] param, int pageNo, int pageSize) throws Exception;/*** 删除一条记录* @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空则不予执行* @return*/boolean delete(T entity) throws Exception;/*** 批量删除* @param list* @return 返回受影响的行数* @throws Exception*/int deleteAll(List<T> list) throws Exception;/*** 插入一条记录并返回插入后的ID* @param entity 只要entity不等于null,就执行插入操作* @return*/PK insertAndReturnId(T entity) throws Exception;/*** 插入一条记录自增ID* @param entity* @return* @throws Exception*/boolean insert(T entity) throws Exception;/*** 批量插入* @param list* @return 返回受影响的行数* @throws Exception*/int insertAll(List<T> list) throws Exception;/***  修改一条记录* @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空则不予执行* @return* @throws Exception*/boolean update(T entity) throws Exception;
}

2.4 QueryRule

如果用QueryRule类来构建查询条件,用户在做条件查询时不需要手写SQL,实现业务代码与SQL解耦。


package com.gupaoedu.vip.orm.framework;import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;/*** QueryRule,主要功能用于构造查询条件*/
public final class QueryRule implements Serializable
{private static final long serialVersionUID = 1L;public static final int ASC_ORDER = 101;public static final int DESC_ORDER = 102;public static final int LIKE = 1;public static final int IN = 2;public static final int NOTIN = 3;public static final int BETWEEN = 4;public static final int EQ = 5;public static final int NOTEQ = 6;public static final int GT = 7;public static final int GE = 8;public static final int LT = 9;public static final int LE = 10;public static final int ISNULL = 11;public static final int ISNOTNULL = 12;public static final int ISEMPTY = 13;public static final int ISNOTEMPTY = 14;public static final int AND = 201;public static final int OR = 202;private List<Rule> ruleList = new ArrayList<Rule>();private List<QueryRule> queryRuleList = new ArrayList<QueryRule>();private String propertyName;private QueryRule() {}private QueryRule(String propertyName) {this.propertyName = propertyName;}public static QueryRule getInstance() {return new QueryRule();}/*** 添加升序规则* @param propertyName* @return*/public QueryRule addAscOrder(String propertyName) {this.ruleList.add(new Rule(ASC_ORDER, propertyName));return this;}/*** 添加降序规则* @param propertyName* @return*/public QueryRule addDescOrder(String propertyName) {this.ruleList.add(new Rule(DESC_ORDER, propertyName));return this;}public QueryRule andIsNull(String propertyName) {this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND));return this;}public QueryRule andIsNotNull(String propertyName) {this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND));return this;}public QueryRule andIsEmpty(String propertyName) {this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND));return this;}public QueryRule andIsNotEmpty(String propertyName) {this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND));return this;}public QueryRule andLike(String propertyName, Object value) {this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andEqual(String propertyName, Object value) {this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andBetween(String propertyName, Object... values) {this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND));return this;}public QueryRule andIn(String propertyName, List<Object> values) {this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(AND));return this;}public QueryRule andIn(String propertyName, Object... values) {this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND));return this;}public QueryRule andNotIn(String propertyName, List<Object> values) {this.ruleList.add(new Rule(NOTIN, propertyName, new Object[] { values }).setAndOr(AND));return this;}public QueryRule orNotIn(String propertyName, Object... values) {this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR));return this;}public QueryRule andNotEqual(String propertyName, Object value) {this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andGreaterThan(String propertyName, Object value) {this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andGreaterEqual(String propertyName, Object value) {this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andLessThan(String propertyName, Object value) {this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule andLessEqual(String propertyName, Object value) {this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(AND));return this;}public QueryRule orIsNull(String propertyName) {this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR));return this;}public QueryRule orIsNotNull(String propertyName) {this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR));return this;}public QueryRule orIsEmpty(String propertyName) {this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR));return this;}public QueryRule orIsNotEmpty(String propertyName) {this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR));return this;}public QueryRule orLike(String propertyName, Object value) {this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(OR));return this;}public QueryRule orEqual(String propertyName, Object value) {this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(OR));return this;}public QueryRule orBetween(String propertyName, Object... values) {this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR));return this;}public QueryRule orIn(String propertyName, List<Object> values) {this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(OR));return this;}public QueryRule orIn(String propertyName, Object... values) {this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR));return this;}public QueryRule orNotEqual(String propertyName, Object value) {this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(OR));return this;}public QueryRule orGreaterThan(String propertyName, Object value) {this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(OR));return this;}public QueryRule orGreaterEqual(String propertyName, Object value) {this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(OR));return this;}public QueryRule orLessThan(String propertyName, Object value) {this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(OR));return this;}public QueryRule orLessEqual(String propertyName, Object value) {this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(OR));return this;}public List<Rule> getRuleList() {return this.ruleList;}public List<QueryRule> getQueryRuleList() {return this.queryRuleList;}public String getPropertyName() {return this.propertyName;}protected class Rule implements Serializable {private static final long serialVersionUID = 1L;private int type;  //规则的类型private String property_name;private Object[] values;private int andOr = AND;public Rule(int paramInt, String paramString) {this.property_name = paramString;this.type = paramInt;}public Rule(int paramInt, String paramString,Object[] paramArrayOfObject) {this.property_name = paramString;this.values = paramArrayOfObject;this.type = paramInt;}public Rule setAndOr(int andOr){this.andOr = andOr;return this;}public int getAndOr(){return this.andOr;}public Object[] getValues() {return this.values;}public int getType() {return this.type;}public String getPropertyName() {return this.property_name;}}
}

2.5 Order

Order类主要用于封装排序规则,代码如下:


package com.gupaoedu.vip.orm.framework;/*** SQL排序组件*/
public class Order {private boolean ascending; //升序还是降序private String propertyName; //哪个字段升序,哪个字段降序public String toString() {return propertyName + ' ' + (ascending ? "asc" : "desc");}/*** Constructor for Order.*/protected Order(String propertyName, boolean ascending) {this.propertyName = propertyName;this.ascending = ascending;}/*** Ascending order** @param propertyName* @return Order*/public static Order asc(String propertyName) {return new Order(propertyName, true);}/*** Descending order** @param propertyName* @return Order*/public static Order desc(String propertyName) {return new Order(propertyName, false);}
}

因篇幅原因,具体的操作类下一篇继续。
关注微信公众号『 Tom弹架构 』回复“Spring”可获取完整源码。

在这里插入图片描述

本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!
如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom弹架构 』可获取更多技术干货!

原创不易,坚持很酷,都看到这里了,小伙伴记得点赞、收藏、在看,一键三连加关注!如果你觉得内容太干,可以分享转发给朋友滋润滋润!

这篇关于30个类手写Spring核心原理之自定义ORM(上)(6)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/643840

相关文章

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.