目录
1.java中,为什么对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用Long 类型。
2.在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度
3.线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这 样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
4.i/o密集型任务或cpu密集型任务,它们的线程池大小一般如何设置
5.TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE 无事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使用此语句。
1.java中,为什么对于需要使用超大整数的场景,服务端一律使用 String 字符串类型返回,禁止使用Long 类型。
在Java中,对于需要处理超大整数的场景,服务端通常推荐使用String类型而不是Long类型来返回数据,主要是基于以下几个原因:
-
精度问题:Java中的
Long
类型是64位的,能表示的整数范围大约是从-9,223,372,036,854,775,808到9,223,372,036,854,775,807。当数值超出这个范围时,就会导致溢出。使用String
类型可以无限制地表示整数,不会遇到溢出问题。 -
序列化与跨平台兼容性:在Web服务的场景中,数据需要在网络间传输。JSON等文本格式是常用的传输格式,它们天然支持字符串类型的大数字表示。如果使用
Long
类型,特别是在某些特定的数值范围或者不同系统间的解析差异,可能会导致精度丢失。例如,JavaScript中的Number类型在处理超过53位精度的数字时也会出现精度问题。 -
可读性和易用性:对于非常大的整数,直接以字符串形式展现更易于阅读和理解,也方便进行文本搜索或比较操作。
-
框架和库的限制:部分Web框架或库在处理大数字时可能存在的bug或限制,比如某些JSON序列化/反序列化库在处理大数值的
Long
类型时可能会出现问题。 -
数据库兼容性:有些数据库系统在处理大整数时,特别是作为主键或唯一标识时,使用字符串可能更加灵活,避免了数据库之间整数大小限制的不一致性。
因此,阿里巴巴Java开发手册中建议在服务端对超大整数使用String
类型返回,这是为了确保数据的准确性和系统的稳定性,尤其是在面对高度可扩展的分布式系统时,这种做法能够有效避免潜在的数据错误和兼容性问题。
2.在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度
在Java中,正则表达式的预编译功能是指通过Pattern.compile()
方法先将正则表达式模式字符串编译成一个Pattern
对象,然后使用这个对象去创建Matcher
对象进行匹配操作。这样做可以带来几个好处,从而有效加快正则匹配速度:
-
编译只执行一次:正则表达式的编译过程是比较耗时的,因为它涉及到语法分析、优化等多个步骤。当你多次使用同一个正则表达式进行匹配时,如果每次都重新编译,会浪费很多时间。通过预编译,这个过程只需要执行一次,之后就可以复用编译好的
Pattern
对象,显著提高效率。 -
优化匹配性能:
Pattern.compile()
方法在编译时会对正则表达式进行优化,生成一个内部表示形式,这个表示形式更加高效,可以直接用于高效的匹配操作。预编译后的Pattern
对象包含了正则表达式的解析树和执行计划,使得后续的匹配操作更加迅速。 -
重复利用性:预编译后的
Pattern
对象可以被多个线程安全地共享(如果正则表达式本身不依赖外部状态),这意味着在多线程环境中,不需要为每个线程都编译一次正则表达式,进一步提高了资源利用率和性能。
示例代码展示如何使用预编译功能:
// 预编译正则表达式
Pattern pattern = Pattern.compile("\\bhello\\b");
// 使用预编译的Pattern对象创建Matcher进行匹配
Matcher matcher1 = pattern.matcher("say hello to the world");
boolean match1 = matcher1.find(); // true
Matcher matcher2 = pattern.matcher("hi there");
boolean match2 = matcher2.find(); // false
在这个例子中,正则表达式"\bhello\b"
(匹配单词"hello")只被编译了一次,并且被两个不同的字符串使用来进行匹配,这比直接在每次matcher()
调用中传入正则表达式字符串要高效得多。
3.线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这 样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Java中的Executors
类提供了创建不同类型线程池的便捷工厂方法,如newFixedThreadPool
, newCachedThreadPool
, newSingleThreadExecutor
等。这些方法虽然简单易用,但它们创建的线程池往往使用了较为固定的配置,不太适合所有场景,特别是对于生产环境中的复杂需求和性能要求较高的应用。相比之下,直接通过ThreadPoolExecutor
构造函数创建线程池具有更高的灵活性和可控性,具体原因如下:
-
资源控制:通过
ThreadPoolExecutor
直接创建线程池,可以让开发者明确指定线程池的核心线程数、最大线程数、队列大小、拒绝策略等关键参数。这样可以根据应用的具体需求精确控制资源使用,避免资源耗尽风险。比如,不合理的队列大小或者没有合适的拒绝策略可能会导致内存溢出或任务丢失。 -
性能优化:直接配置线程池参数能够针对特定的应用场景进行性能调优。例如,对于I/O密集型任务,可以设置较大的线程池大小,而对于CPU密集型任务,则应限制线程数量以避免过多的上下文切换开销。
-
避免默认配置陷阱:
Executors
的一些方法提供了看似方便的默认配置,但实际上可能隐藏了潜在问题。例如,newFixedThreadPool
使用的无界队列可能会导致内存耗尽;newCachedThreadPool
理论上可以无限创建线程,可能会耗尽系统资源。直接使用ThreadPoolExecutor
可以避免这些默认设置带来的潜在风险。 -
明确意图:直接使用
ThreadPoolExecutor
构造函数创建线程池迫使开发者明确思考和指定线程池的每一个配置项,这有助于提高代码的可读性和可维护性,也让团队成员更容易理解线程池的设计意图和潜在影响。 -
更好的异常处理:直接配置线程池允许开发者自定义
RejectedExecutionHandler
(拒绝策略),这样可以根据应用逻辑灵活处理无法接受的任务,而不是简单地丢弃或抛出异常。
因此,推荐直接使用ThreadPoolExecutor
来创建线程池,虽然这要求开发者对线程池的工作原理有更深的理解,但长远来看,这有助于构建更加健壮、可维护和高性能的应用系统。
4.i/o密集型任务或cpu密集型任务,它们的线程池大小一般如何设置
对于I/O密集型任务和CPU密集型任务,线程池大小的推荐设置是不同的,这是基于它们各自的特点来优化性能和资源利用率:
-
CPU密集型任务:这类任务的特点是程序的执行大部分时间都在进行计算,几乎不涉及I/O操作,因此线程大部分时间都在占用CPU资源。在这种情况下,线程池的大小通常设置为接近系统可用的CPU核心数(通常是
N+1
或N
,其中N
是CPU核心数)。这样可以充分利用CPU资源,同时避免过多的线程导致上下文切换的开销。额外的一个线程有时被建议用来应对某些线程可能因为等待短暂的I/O操作(如页面错误)而暂停的情况,保持CPU的充分利用。 -
I/O密集型任务:对于I/O密集型任务,由于任务在执行过程中会花费大量时间等待I/O操作完成(如文件读写、网络通信等),此时线程并不占用CPU。因此,可以设置较大的线程池大小,以便在等待I/O时,CPU可以处理其他线程的任务,提高整体的吞吐量。一般推荐的线程数为CPU核心数的两倍(
2N
),这样可以确保在I/O阻塞时有足够的线程准备运行,充分利用CPU时间。
需要注意的是,这些只是大致的指导原则,实际应用中可能需要根据具体情况调整。例如,如果任务的性质混合了I/O和CPU操作,或者系统的其他因素(如内存限制、任务的平均执行时间等)也需要考虑。此外,监控和压力测试是优化线程池大小的有效手段,通过实际运行测试来微调参数以达到最佳性能。
5.TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少,但 TRUNCATE 无事务且不触发 trigger,有可能造成事故,故不建议在开发代码中使用此语句。
TRUNCATE TABLE
和DELETE
都是用于删除表中数据的SQL语句,但它们在性能、资源使用、事务处理和触发器触发方面有所不同
-
速度:
TRUNCATE TABLE
通常比DELETE
快,因为它直接删除表的数据页,而不是逐行删除数据。这使得TRUNCATE TABLE
在处理大量数据时更加高效。 -
系统和事务日志资源:
TRUNCATE TABLE
不记录每一行的删除操作,因此它使用的系统和事务日志资源相对较少。这使得TRUNCATE TABLE
在处理大量数据时对系统资源的影响更小。 -
事务处理:
TRUNCATE TABLE
是一个DDL(数据定义语言)操作,不属于事务处理范畴。这意味着它不能被回滚,也就是说,一旦执行TRUNCATE TABLE
,数据就无法恢复。相比之下,DELETE
是一个DML(数据操作语言)操作,可以被事务处理,可以回滚。 -
触发器触发:
TRUNCATE TABLE
不触发触发器,因为它不逐行删除数据。这使得TRUNCATE TABLE
在执行时不会触发与表关联的触发器。相比之下,DELETE
会触发触发器,因为它逐行删除数据。
由于TRUNCATE TABLE
的这些特性,它在某些情况下可能更适合用于删除大量数据。然而,由于它不属于事务处理,且不触发触发器,因此在使用时需要特别小心。在开发代码中,为了确保数据的完整性和安全性,通常建议使用DELETE
而不是TRUNCATE TABLE
,尤其是在涉及到触发器和事务处理的场景中。
在实际应用中,选择使用TRUNCATE TABLE
还是DELETE
取决于你的需求和场景。如果你需要删除大量数据,并且不关心事务处理和触发器触发,可以考虑使用TRUNCATE TABLE
。如果你需要保留事务处理和触发器触发,或者只需要删除部分数据,建议使用DELETE
。
6.java中按指定长度截取字符串落库到oracle报错提示长度不够
oracle的doc_desction字段为varchar2(12),java中对字符"jomi_test结转单"进行length()长度进行判断后进行截图,报错。
public static void main(String[] args) {
String a = "jomi_test结转单";
if(a.length()>12){
System.out.println(a.substring(0,12));
}
System.out.println("a的长度是:"+a.length());
}
运行结果==》
a的长度是:12
报错:0RA-12899:value too large for cloumn..
经排除,需要按照字节进行计算字符串长度并进行无损截取(精确地考虑不同字符类型的截取,区分中英文等。如果不区分截取后可能出现乱码)。代码如下:
public static void main5(String[] args) {
StringBuilder sb = new StringBuilder();
String a = "jomi_test1结";
// 对应VARCHAR2(12)的字节长度限制
int maxByteLength = 12;
byte[] bytes = a.getBytes(StandardCharsets.UTF_8);
System.out.println("a的长度是:"+bytes.length);
int currentByteLength = 0;
for (char c : a.toCharArray()) {
byte[] charBytes = String.valueOf(c).getBytes(StandardCharsets.UTF_8);
if (currentByteLength + charBytes.length <= maxByteLength) {
sb.append(c);
currentByteLength += charBytes.length;
} else {
break;
}
}
String truncatedString = sb.toString();
System.out.println(truncatedString);
}
运行结果:
a的长度是:13
jomi_test1