# 后端开发技巧、常用规范
后端开发技巧、常用规范
开发技巧
equals() 方法的使用
null.equals()
会出报空指针,因该是非null
的值.equals()
- 可以使用
Objects
的equals()
方法避免空值,完美
String strOne = null;
String strTwo = null;
boolean oneFlag = Objects.equals(strOne, strTwo);
- 忽略大小写:
equalsIgnoreCase()
创建 HashMap 指定初始化大小
public HashMap(int initialCapacity) {this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
initialCapacity = (需要存储的元素个数/负载因子)+1
。负载因子默认为0.75
当不指定
HashMap
的大小会发生多次扩容会影响效率。比如map
中有1000个元素,至少要将容量设置为1000/0.75=1333+1=1334
,如果不设置大小那么就会多次扩容,比较影响效率。当无法估计大小的时候,请设置为
HashMap
的默认大小16
Optional.ofNullable().orElse() 避免空指针
通过Optional.ofNullable().orElse()
避免空指针,例如遍历从map
中拿到的某个list
,原始代码如下:
Map<String,Object> map = new HashMap<>(16);
map.put("list",null);List<Map<String ,Object>> list = (List<Map<String, Object>>) map.get("list");
// list 会报控指针
for (Map<String, Object> item : list) {logger.info(String.valueOf(item));
}
- 使用
Optional
完美解决
Map<String,Object> map = new HashMap<>(16);
map.put("list",null);List<Map<String ,Object>> list = Optional.ofNullable((List < Map < String, Object >> ) map.get("list")).orElse(new ArrayList<>());
for (Map<String, Object> item : list) {logger.info(String.valueOf(item));
}
- 使用
Optional
选择默认数据
User user1 = new User(1, "张三", "西安");
User user2 = new User(2, "李四", "新疆");user1 = null;
User user = Optional.ofNullable(user1).orElseGet(() -> user2);
logger.info(user.toString());
Stream 求和
- 使用
Stream
流遍历集合中的元素进行求和操作
List<Double> doubleList = Arrays.asList(12.2, 13.45, 12.4);
double sumOne = doubleList.stream().mapToDouble(x -> x).sum();
logger.info("sumOne:{}", sumOne);List<BigDecimal> decimalList = new ArrayList<>();
decimalList.add(new BigDecimal("12.3"));
decimalList.add(new BigDecimal("12.3"));
decimalList.add(new BigDecimal("12.3"));
BigDecimal bigDecimal = decimalList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
logger.info("bigDecimal:{}", bigDecimal.floatValue());
logger.info("bigDecimal:{}", bigDecimal.doubleValue());List<Object> objectList = Arrays.asList(12, 13, 1);
int sum = objectList.stream().mapToInt(x -> (int) x).sum();
logger.info("sum:{}", sum);
List 切割工具
Lists.partition()
for (List<DataDto> dataDtos : Lists.partition(list, 1000)) {dataDtoMapper.insertBatch(dataDtos);
}
- 依赖
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.0.1-jre</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion></exclusions>
</dependency>
单例类或者工具类 添加私有构造方法
- 工具类或者单例类提供私有的构造函数,没有过多的功能,提供私有构造函数防止外部使用污染。
类变量(集合)应该在使用完成之后清空,避免内存泄漏
- 应该及时销毁没用的对象,如果对象过大,虚拟机没办法垃圾回收的时候,有可能造成内存泄漏,所以使用完就清空.
private static final Map<String, Object> TABLE_COLUMN_MAP = new HashMap<>();// 清空集合
TABLE_COLUMN_MAP.clear();
使用 ThreaadLocal 后需要释放资源防止内存泄漏
private ThreadLocal<Map<String, String>> threadLocalMap = new ThreadLocal<>();@Test
public void test1() {Map<String, String> map = new HashMap<>();map.put("test1", "张三");map.put("test2", "李四");threadLocalMap.set(map);getThreadLocalMap();threadLocalMap.remove();
}
巧妙使用设计模式
巧妙使用接口、抽象类
Java
设计模式请看:https://blog.csdn.net/qq_37248504/article/details/117753021
Spring 工厂模式的结合使用
Java
工厂模式请看:https://blog.csdn.net/qq_37248504/article/details/117753021- 使用
Spring
收集Bean
对象放到一个Map
中,从这个Map
中拿到相应的对象的实例,直接上代码 - 接口
CustomerService.java
public interface CustomerService {/*** 获取用户姓名* @return*/String getUserName();/*** 注册*/void registered();/*** 登录*/void login();
}
- 接口的实现类:需要收集的对象实例可以有很多个实例
@Service
public class CustomerServiceOneImpl implements CustomerService {@Overridepublic String getUserName() {return "CustomerOne";}@Overridepublic void registered() {}@Overridepublic void login() {}
}@Service
public class CustomerServiceTwoImpl implements CustomerService {@Overridepublic String getUserName() {return "CustomerTwo";}@Overridepublic void registered() {}@Overridepublic void login() {}
}
- 工厂方法:可以使用
set
注入、或者构造函数方式、或者从当前上下文中拿到接口的实例对象
@Component
public class CustomerFactory {/*** 对象 Map*/private static final Map<String, CustomerService> OBJECT_MAP = new HashMap<>();/*** set 方法注入** @param customerService*/@Autowiredprivate void setObjectMap(List<CustomerService> customerService) {for (CustomerService service : customerService) {OBJECT_MAP.put(service.getUserName(), service);}}/*** 获取 CustomerService 的实例** @param type* @return*/public static CustomerService getInstance(String type) {return OBJECT_MAP.get(type);}}
- 测试
/*** Spring 工厂模式测试*/
@Override
public void testFive() {CustomerFactory.getInstance("CustomerOne").registered();CustomerFactory.getInstance("CustomerTwo").registered();
}
- 完整代码请看:https://gitee.com/Marlon_Brando/back/commit/d9ad24564dfe1459ec9e0728822b709f1ea6fa41
Spring、SpringBoot 经常使用技巧
获取容器中的
Bean
、Bean
的初始化更多详情请看:https://blog.csdn.net/qq_37248504/article/details/113896952
Stream 流等操作时候使用方法的引用
Stream
List<String> collect = list.stream().filter("lisi"::equals).map(String::toUpperCase).collect(Collectors.toList());
collect.forEach(System.out::println);list.removeIf("李四"::equals);
HashMap
Map<String, String> map = new HashMap<String, String>() {{put("one", "one");put("two", "one");put("three", "one");
}};
Map<String, String> mapOne = new HashMap<>();
map.forEach(mapOne::put);
logger.info(String.valueOf(mapOne));
Java 创建线程池
- 使用
ThreadPoolExecutor
创建线程池,使用线程,到处new Thread()
没有回收造成资源浪费,因该交给线程池去管理线程。
public class ThreadPooTest {private static final Logger logger = LoggerFactory.getLogger(ThreadPooTest.class);private static final long THREAD_TIME_OUT = 60;@Testpublic void test() {// Cpu 核数int cpuNum = Runtime.getRuntime().availableProcessors();// 最大数int maxSize = 2 * cpuNum + 1;/*** 拒绝策略:当阻塞队列和最大线程都用完之后** AbortPolicy:ThreadPoolExecutor中默认的拒绝策略就是AbortPolicy。直接抛出异常。* CallerRunsPolicy:在任务被拒绝添加后,会调用当前线程池的所在的线程去执行被拒绝的任务。* DiscardPolicy:会让被线程池拒绝的任务直接抛弃,不会抛异常也不会执行。* DiscardOldestPolicy:当任务呗拒绝添加时,会抛弃任务队列中最旧的任务也就是最先加入队列的,再把这个新任务添加进去。*/ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(cpuNum,maxSize,THREAD_TIME_OUT,TimeUnit.SECONDS,new ArrayBlockingQueue<>(20),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());poolExecutor.execute(new Thread(() -> {logger.info(Thread.currentThread().toString());}));}
}
Spring Boot 配置全局的线程池
@Configuration
@EnableAsync
public class ThreadPoolConfig {private static final Logger logger = LoggerFactory.getLogger(ThreadPoolConfig.class);@Beanpublic Executor globalExecutor() {// 获取当前cpu核数int cpuNum = Runtime.getRuntime().availableProcessors();ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();poolExecutor.setCorePoolSize(cpuNum);//配置最大线程数poolExecutor.setMaxPoolSize(cpuNum * 2);//配置队列大小poolExecutor.setQueueCapacity(300);//线程存活时间poolExecutor.setKeepAliveSeconds(60);//配置线程池中的线程的名称前缀poolExecutor.setThreadNamePrefix("globalExecutor");// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//执行初始化poolExecutor.initialize();logger.info(LogConstant.FLAG);logger.info(LogConstant.LOG_SUCCESS_PREFIX + "Spring 全局线程池初始化完成......");logger.info(JSON.toJSONString(poolExecutor));logger.info(LogConstant.FLAG);return poolExecutor;}
}
- 使用
/*** 全局线程池配置测试*/
@Async("globalExecutor")
@Override
public void globalExecutorTest() {logger.info("test thread!");
}
Idea 热部署插件:Jrebel
Idea
社区版能满足常用的开发,支持maven
、gradle
项目,真的没有必要破解Idea
,哈哈哈哈哈哈哈哈。使用特别
Nice
基本上不用重启服务,网上都有注册码。
初始化 Map
- 惯例
Map<String, String> mapTwo = new HashMap<>();
mapTwo.put("a", "b");
mapTwo.put("c", "d");
java8
新特性:双括号初始化
Map<String, String> mapOne = new HashMap<String, String>() {{put("one", "testOne");put("two", "testTwo");put("three", "testThree");}
};
com.google.guava
中的方法
ImmutableMap<String, Integer> map = ImmutableMap.of("a", 1, "b", 2, "c", 3);
logger.info(String.valueOf(map));
List 初始化
- 构造
List
,add()
List<String> listOne = new ArrayList<>();
listOne.add("test");
listOne.add("test");
- 双括号语法
List<String> listTwo = new ArrayList<String>(){{add("one");add("one");add("one");
}};
Arrays.asList()
List<String> listThree = Arrays.asList("one", "two", "three");
Stream.of()
List<String> listFour = Stream.of("testone", "testtwo", "testthree").collect(Collectors.toList());
com.google.guava
中的方法
ArrayList<String> listFive = Lists.newArrayList("one", "two", "three");
后端统一返回对象(泛型使用)
- 静态方法
success
、error
public class ResponseInfo<T> {/*** 状态码*/private Integer code;/*** 信息*/private String message;/*** 返回结果*/private T data;public ResponseInfo() {}public ResponseInfo(Integer code, String message) {this.code = code;this.message = message;}public ResponseInfo(Integer code, String message, T data) {this.code = code;this.message = message;this.data = data;}/*** 失败** @param code* @param message* @param <T>* @return*/public static <T> ResponseInfo<T> error(Integer code, String message) {return new ResponseInfo<>(code, message);}/*** 成功** @param code* @param message* @return*/public static <T> ResponseInfo<T> success(Integer code, String message) {return new ResponseInfo<>(code, message);}/*** 成功标志** @param code* @param message* @param object* @return*/public static <T> ResponseInfo<T> success(Integer code, String message, T object) {return new ResponseInfo<>(code, message, object);}
}
return 空的集合代替 return null
- 避免空指针问题
return Collections.emptyList();
return Collections.emptyMap();
return Collections.emptySet();
使用 String.valueof() 防止强制转换报错
valueOf()
方式可以避免类型转换异常
@Test
public void testOne() {Integer one = 24;BigDecimal two = new BigDecimal(23);Map<String, Object> map = new HashMap<>();map.put("one", one);map.put("two", two);// 报错String strOne = (String) map.get("one");String strTwo = (String) map.get("two");// 正常使用String strThree = String.valueOf(map.get("one"));String strFour = String.valueOf(map.get("two"));
}
- 尽量使用
valueof()
方法避免转换异常
String.join()拼接集合中的元素
// 拼接迭代器中的元素
List<String> list = Arrays.asList("zhangsan", "lisi", "wangwu");
String joinStr = String.join("','", list);
logger.info(joinStr);
// zhangsan','lisi','wangwu
TreeSet 排序
@Test
public void treeSetTest() {TreeSet<String> set = new TreeSet<String>((Comparator) (o1, o2) -> {int length1 = String.valueOf(o1).length();int length2 = String.valueOf(o2).length();if (length1 == length2) return 1;return Integer.compare(length1, length2);});set.add("zhangsan");set.add("test");set.add("lisi");set.add("1234");set.add("wangwu");logger.info(String.valueOf(set));
}
Map 做缓存
- 使用
Map
可以做本地的部分缓存,将常用的对象例如工具类等可以放在缓存当中,从缓存中取值, - 注意
Map
作为缓存的时候,确定使用恰当。
final 的使用场景
- 不允许被继承的类,如:String 类
- 不允许修改引用的域对象,如:POJO 类的域变量
- 不允许被重写的方法
- 不允许运行过程中重新赋值的局部变量
for 循环移除元素
- 不要在
foreach
循环里进行元素的remove/add
操作。remove
元素请使用Iterator
方式,如果并发操作,需要对 Iterator
对象加锁。
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) { String item = iterator.next(); if (删除元素的条件) { iterator.remove(); }
}
遍历Map
- 使用
entrySet
遍历Map
类集合KV
,而不是keySet
方式进行遍历。
for (Map.Entry<String, String> entry : map.entrySet()) {logger.info("键:{}", entry.getKey());logger.info("值:{}", entry.getValue());
}
集合空值说明
集合类 | key | value | super | 说明 |
---|---|---|---|---|
HashMap |
允许为null
|
允许为null
|
AbstractMap | 线程不安全 |
TreeMap |
不允许为null
|
允许为null
|
AbstractMap | 线程不安全 |
ConcurrentHashMap |
不允许为null
|
不允许为null
|
AbstractMap | 线程安全 |
Hashtable |
不允许为null
|
不允许为null
|
Dictionary | 锁分段技术(JDK8:CAS) |
Git删除add的文件
git rm --cached 文件名
Git重新 commit
- 使用
Idea
的undo commit
撤销上次的commit
重新来。
Git重新 commit(还没有push到远端)
reset Mixed
之前Commit
修改的内容会保留。reset Hard
之前Commit
修改的内容不会保留。reset Soft
类似于reset Mixed
,但是又区别。比如上次的commit
中有个新建的文件,当使用reset Mixed
命令时候,撤销commit
后这个新建的文件是没有进行add
操作的,文件的颜色是红色的。使用reset Soft
命令这个文件是进行了add
操作了的。
利用Set去重
注意重写
equals()
和hash()
,可以根据实际业务场景进行去重操作,例如如果商品编号相等那么断定这个商品是同一件商品。重写对象的equals()
@Override
public boolean equals(Object object) {if (this == object) return true;if (Objects.isNull(object) || getClass() != object.getClass()) return false;Shop shop = (Shop) object;return (Objects.nonNull(shop) ? shopCode.equals(shop.getShopCode()) : shop == null);
}
- 重写对象的hash()
@Override
public int hashCode() {return Objects.isNull(shopCode) ? 0 : shopCode.hashCode();
}
异常处理
- java异常
class Throwable;
class Exception;
class Error;
- 处理方法:
向上抛异常:最底层的代码例如工具类,直接向上抛原始异常就行了。
输出原始异常:如果是捕获到了异常,那么一定要输出原始异常的信息,如果只是输出e.getMessage
无法定位到代码出错的行数,如果是空指针错误信息都没有。
使用日志框架层:例如log4j
优雅的抛出异常
- 使用
Objects
@Test
public void testFive() {String str = null;Objects.requireNonNull(str, "str is null!");
}
- 使用
Assets
@Test
public void testSix() {String str = null;Assert.notNull(str, "str is null!");
}
Mybatis 使用技巧
- 详见:https://blog.csdn.net/qq_37248504/article/details/106932085
Oracle Mybatis 常用语法、报错处理
- 详见:https://blog.csdn.net/qq_37248504/article/details/118367963
Sql 常用语句
- 详见:https://blog.csdn.net/qq_37248504/article/details/116171452
常用规范
其实使用
Idea
开发的时候,开启Idea
自带的代码检测,处理掉所有的告警大部分代码问题会解决,代码命名规范等可以使用阿里巴巴开发规范插件,使用SonarLint
插件可以处理一些垃圾代码,可以扫描一些静态的错误,从而提高代码质量。
SonarLint 检查提示和解决方法
- 详细请看:https://blog.csdn.net/qq_37248504/article/details/115266913
类的命名
- 使用驼峰式命名的规范。
DO、 DTO 、 VO
等除外
UserDO
UserDTO
UserVO
- 在模块或者接口,类,方法中使用了设计模式,那么请在命名的时候体现出来。
CompomentFactory
AbstractPrint
pojo 类中的属性使用包装类
基本类型会有默认值,使用包装内可以设置为
null
pojo
的getter
和setter
方法里面不要增加业务逻辑。
抛出异常的时候确定异常的类型,可以定义自己的异常抛出
public class MyException extends RuntimeException {public MyException() {}public MyException(String message) {super(message);}public MyException(String message, Throwable cause) {super(message, cause);}public MyException(Throwable cause) {super(cause);}public MyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {super(message, cause, enableSuppression, writableStackTrace);}
}
- 使用
/*** 抛出自定义异常,测试自定义异常处理器*/
@GetMapping("/myexception")
public String createMyException() throws MyException {throw new MyException("MyException 自定义异常信息");
}
在 for 循环中拼接字符串使用 StringBuilder
StringBuilder strOne = new StringBuilder("test");
for (int i = 0; i < 10000000; i++) {strOne.append(strOne);
}
不要使用魔法值(常量)
- 使用接口在接口中定义常量
- 维护常量类
- 使用枚举类
final 的使用
- 类、方法、变量能用就可以加上
final
防止重写、继承。
避免创建不必要的对象
- 不要随便创建对象
- 例如在
for
循环中尝试使用同一对象处理等。 - 可以使用
Map
做常用对象的缓存
组合优先于继承
- 继承有利于代码复用,但是尽可能不要进行跨包的继承。
- 组合,即不扩展已有的类,而是在的类中新增一个现有类的。
用枚举代替常量值
Color.java
public enum Color {RED("red", "红色"), GREEN("green", "绿色");private String name;private String title;Color(String name, String title) {this.name = name;this.title = title;}public String getName() {return name;}public String getTitle() {return title;}
}
接口优先于反射机制
使用反射机制会带来以下的问题:
- 丧失了编译期类型检查
- 代码笨拙冗长
- 性能损失
反射基本上只适合用在编写组件时、代码分析器、RPC
等场景下使用。在使用反射机制时,如果可能,尽可能只通过反射机制实例化对象,而访问方法时,使用已知的接口或者超类。
命名风格(阿里巴巴规范)
代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束
类名使用驼峰规则,DO、BO、DTO、VO等除外
方法名、参数名、成员变量、局部变量都统一使用
lowerCamelCase
风格,必须遵从驼峰形式。
抽象类命名使用
Abstract
或Base
开头;异常类命名使用Exception
结尾;测试类命名以它要测试的类的名称开始,以
Test
结尾。中括号是数组类型的一部分,数组定义如下:
String[] args
为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词
组合来表达其意。
对于
Service
和DAO
类,基于SOA
的理念,暴露出来的服务一定是接口,内部的实现类用Impl
的后缀与接口区别。类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 >
getter/setter
方法
各层命名规范(阿里巴巴规范)
- 获取单个对象的方法用 get 做前缀。
- 获取多个对象的方法用 list 做前缀。
- 获取统计值的方法用 count 做前缀。
- 插入的方法用 save/insert 做前缀。
- 删除的方法用 remove/delete 做前缀。
- 修改的方法用 update 做前缀。
类成员与方法访问控制(阿里巴巴规范)
- 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是
private
。 - 工具类不允许有
public
或default
构造方法 - 类非
static
成员变量并且与子类共享,必须是protected
- 类非
static
成员变量并且仅在本类使用,必须是private
- 类
static
成员变量如果仅在本类使用,必须是private
。 - 若是
static
成员变量,必须考虑是否为final
- 类成员方法只供类内部调用,必须是
private
- 类成员方法只对继承类公开,那么限制为
protected
工具类
镜像源、常用工具
- 详见:https://blog.csdn.net/qq_37248504/article/details/118605663
Markdown
- 详见:https://blog.csdn.net/qq_37248504/article/details/109085445
Linux、DOS常用命令
- 详见:https://blog.csdn.net/qq_37248504/article/details/106866545
好用工具推荐
- 数据库连接工具:免费的
Dbeaver
(支持各种数据库):https://dbeaver.io/ Markdown
语法工具:Typora
:https://typora.io/Redis
客户端: https://gitee.com/qishibo/AnotherRedisDesktopManager
# 后端开发技巧、常用规范相关推荐
- 连夜整理了多年后端开发最常用linux指令(建议收藏,边用边学)
0. 引言 前段时间有同学问我:linux指令那么多,怎么去学?实际上这个问题也曾经困扰着我,多年走来,我总结了一个经验:优先学习你马上要用到的,而不是上来就体系的全部学习一遍. 可能很多同学会不太适 ...
- 后端开发中常用的语言
1.C/C++ 语言 C 语言最初是用于系统开发工作,特别是组成操作系统的程序.由于 C 语言所产生的代码运行速度与汇编语言编写的代码运行速度几乎一样,所以采用 C 语言作为系统开发语言.目前,C 语 ...
- Java后端开发工程师技术栈整理
文章目录 Java后端开发工程师技术栈整理 常用工具 Java IDE 数据库客户端 数据库建模工具 SSH客户端 文本编辑器 Markdown编辑器 API调试工具 浏览器 压力测试工具 DevOp ...
- Go 学习笔记(83)— 编码规范及常用开发技巧
UBER 开源的 Go 语言开发规范 1. 规范指南 1.1 包名 package 的命名应该遵循如下原则: 只由小写字母组成.不包含大写字母和下划线等字符: 简短并包含一定的上下文信息.例如 tim ...
- 大话后端开发的奇淫技巧大集合
Hi,大家好,很荣幸有这个机会可以通过写博文的方式,把这些年在后端开发过程中总结沉淀下来的经验和设计思路分享出来 模块化设计 根据业务场景,将业务抽离成独立模块,对外通过接口提供服务,减少系统复杂度和 ...
- pycharm快速添加函数及参数注释_后端开发使用pycharm的技巧
后端开发使用pycharm的技巧 1.使用说明 首先说明,本文所使用的功能为pycharm专业版所支持,其他版本如社区版,教育版,则不一定支持. 作为一名后端开发,我猜你的桌面上一定打开着一系列的软件 ...
- JS~~~ 前端开发一些常用技巧 模块化结构 命名空间处理 奇技淫巧!!!!!!...
前端开发一些常用技巧 模块化结构 &&&&& 命名空间处理 奇技淫巧!!!!!!2016-09-29 17 ...
- 后端开发(1)---大话后端开发的技巧大集合
大话后端开发的技巧大集合 模块化设计 根据业务场景,将业务抽离成独立模块,对外通过接口提供服务,减少系统复杂度和耦合度,实现可复用,易维护,易拓展 项目中实践例子: Before: 在返还购APP里有 ...
- 后端开发工程师开发规范
1 开发规范 1.1 开发流程 明确: 为什么要做这个东西,它的价值在哪里(意义) 这个东西要实现什么功能,它面向的用户是谁(目标用户群体) 它的功能后续可以有什么发展(长远性,功能扩展) 前期需求的 ...
最新文章
- 干货丨你知道Python中a += b和a = a + b的结果是不一样的吗?
- spring配置文件注解方式引入的两种方式
- 实例20:python
- 分数小数互换图_重复控制器学习心得(二)——超前环节的分数化和校正因子的引入...
- 《大道至简》阅读笔记
- 拓端tecdat|R语言实现MCMC中的Metropolis–Hastings算法与吉布斯采样
- ADSL路由切换IP
- [机器学习入门] 经典台大李宏毅机器学习课程从这里开始
- 在mac 上安装 mpkg
- DPDK Release 20.05
- Mysql中有关Datetime和Timestamp的使用总结
- docker CLI官方教程 run方法解析(docer run 、docker attach 与 docker exec的区别)
- 普物期末题型总结题解
- 分形图java_数字的美丽——分形图形
- (七)继续对话库检索的闲聊系统
- IOC和DI浅显易懂的理解
- 竞品分析怎么做?6步完成竞品分析报告
- 目标检测 | End-to-end Lane Detection through Differentiable Least-Squares Fitting
- 安卓手机管理软件_手机文件管理真的很难吗?
- 中学阶段的常见疑惑及回复