java代码调优,java优化代码常见套路
永远的神干货盘点
1.用字符串。格式拼接字符串
不知道你有没有拼接过字符串,特别是那种有多个参数,字符串比较长的情况。
比如现在有个需求:要用得到请求调用第三方接口,网址后需要拼接多个参数。
以前我们的请求地址是这样拼接的:
String url=http://susan.sc.cn?用户名=用户名年龄=年龄地址=地址性别=性别角色id=角色id;String url=http://susan.sc.cn?用户名=用户名年龄=年龄地址=地址性别=性别角色id=角色id;
字符串使用号拼接,非常容易出错。
后面优化了一下,改为使用StringBuilder拼接字符串:
StringBuilder URL builder=new StringBuilder( http://Susan。即cn?);
urlBuilder.append(userName=)。追加(用户名)。追加(年龄=)。附加(年龄)。追加( address=)。追加(地址)。append( sex=)。追加(性别)。append( roledId=)。追加(角色did);代码优化之后,稍微直观点。
但还是看起来比较别扭。
这时可以使用字符串。格式方法优化:
字符串请求URL= http://Susan。即cn?用户名=%s年龄=%s地址=%s性别=%s角色Id=%s
字符串URL=字符串。格式(请求URL,用户名,年龄,地址,性别,角色id);代码的可读性,一下子提升了很多。
我们平常可以使用字符串。格式方法拼接全球资源定位器(统一资源定位器)请求参数,日志打印等字符串。
但不建议在为循环中用它拼接字符串,因为它的执行效率,比使用号拼接字符串,或者使用StringBuilder拼接字符串都要慢一些。
2.创建可缓冲的超正析象管(图片Orthicon)流超正析象管(图片Orthicon)流想必大家都使用得比较多,我们经常需要把数据写入某个文件,或者从某个文件中读取数据到内存中,甚至还有可能把文件一,从目录b,复制到目录c下等。
爪哇岛开发工具包给我们提供了非常丰富的API,可以去操作超正析象管(图片Orthicon)流。
例如:
公共类IoTest1 {
公共静态void main(String[] args) {
FileInputStream fis=null
FileOutputStream fos=null
尝试{
File src File=new File(/Users/dv _ Susan/Documents/workspace/jump/src/main/Java/com/sue/jump/service/test1/1。txt’);
File destFile=new File(/Users/dv _ Susan/Documents/workspace/jump/src/main/Java/com/sue/jump/service/test1/2。txt’);
fis=新文件inputstream(src文件);
fos=新文件输出流(dest文件);
int len
while ((len=fis.read())!=-1) {
福斯。write(len);
}
福斯。flush();
} catch (IOException e) {
e。printstacktrace();
}最后{
尝试{
如果(fos!=null) {
福斯。close();
}
} catch (IOException e) {
e。printstacktrace();
}
尝试{
如果(fis!=null) {
fis。close();
}
} catch (IOException e) {
e。printstacktrace();
}
}
}
}这个例子主要的功能,是将1.txt文件中的内容复制到2.txt文件中。这例子使用普通的超正析象管(图片Orthicon)流从功能的角度来说,也能满足需求,但性能却不太好。
因为这个例子中,从1.txt文件中读一个字节的数据,就会马上写入2.txt文件中,需要非常频繁的读写文件。
优化:
公共类IoTest
公共静态void main(String[] args) {
BufferedInputStream bis=null
BufferedOutputStream bos=null
FileInputStream fis=null
FileOutputStream fos=null
尝试{
File src File=new File(/Users/dv _ Susan/Documents/workspace/jump/src/main/Java/com/sue/jump/service/test1/1。txt’);
File destFile=new File(/Users/dv _ Susan/Documents/workspace/jump/src/main/Java/com/sue/jump/service/test1/2。txt’);
fis=新文件inputstream(src文件);
fos=新文件输出流(dest文件);
bis=新缓冲区输入流(fis);
bos=新BufferedOutputStream(fos);
字节[]缓冲区=新字节[1024];
int len
while ((len=bis.read(buffer))!=-1) {
bos.write(buffer,0,len);
}
博斯。flush();
} catch (IOException e) {
e。printstacktrace();
}最后{
尝试{
如果(bos!=null) {
博斯。close();
}
如果(fos!=null) {
福斯。close();
}
} catch (IOException e) {
e。printstacktrace();
}
尝试{
如果(bis!=null) {
之二。close();
}
如果(fis!=null) {
fis。close();
}
} catch (IOException e) {
e。printstacktrace();
}
}
}
}
此示例使用BufferedInputStream和BufferedOutputStream创建缓冲的iostream。
重点是定义了一个缓冲字节数组,临时保存从1.txt文件中读取的数据,然后将缓冲字节数组的数据一次性批量写入2.txt。
这样做的好处是减少了读写文件的次数,我们都知道读写文件是一个非常耗时的操作。也就是说,使用可缓存的iostream可以提高IO的性能,尤其是在文件大小非常大的情况下,效率会有明显的提升。
3.减少循环次数。在我们的日常开发中,在布景中循环是一项必不可少的操作。
但如果循环层次较深,循环陷入循环,可能会影响代码的执行效率。
反例:
for(用户用户:用户列表){
对于(角色role: roleList) {
if(user.getRoleId()。equals(role . getid()){
user . set rolename(role . getname());
}
}
}在这个例子中,有两层循环。如果userList和roleList中有更多的数据,我们需要多次循环遍历它们才能得到我们需要的数据,这就消耗了大量的cpu资源。
示例:
Map Long,列出角色roleMap=roleList.stream()。collect(collectors . grouping by(Role:getId));
for(用户用户:用户列表){
list Role roles=Role map . get(user . getroleid());
if(collection utils . isnotempty(roles)){
user.setRoleName(roles.get(0))。getName());
}
}要减少循环次数,最简单的办法就是把第二层的循环集合变成一个地图,这样你就可以直接通过key得到想要的数值数据。
虽然map的键有hash冲突,但是遍历存储数据的链表或红黑树的时间复杂度要比遍历整个列表集小得多。
4.资源用完了记得及时关闭。在我们的日常开发中,可能会经常访问资源,比如:获取数据库连接、读取文件等。
让我们以获取数据库连接为例。
反例:
//1.加载驱动程序类
class . forname( com . MySQL . JDBC . driver );
//2.创建连接
connection connection=driver manager . getconnection( JDBC:MySQL//localhost:3306/db?allowMultiQueries=true use unicode=true character encoding=UTF-8 , root , 123456 );
//3.编写sql
String sql= select * from user
//4.创建PreparedStatement
prepared statement pstmt=conn . prepare statement(SQL);
//5.获取查询结果
ResultSet RS=PS TMT . execte query();
while(rs.next()){
int id=RS . getint( id );
string name=RS . getstring( name );
}上面的代码工作正常,但是犯了一个大错误,就是ResultSet、PreparedStatement、Connection对象的资源在使用后没有关闭。
众所周知,数据库连接是一项非常宝贵的资源。我们不能一直创建连接,用完了也不会回收,白白浪费数据库资源。
示例:
//1.加载驱动程序类
class . forname( com . MySQL . JDBC . driver );
Connection connection=null
PreparedStatement pstmt=null
结果集rs=null
尝试{
//2.创建连接
connection=driver manager . getconnection( JDBC:MySQL//localhost:3306/db?allowMultiQueries=true use unicode=true character encoding=UTF-8 , root , 123456 );
//3.编写sql
String sql= select * from user
//4.创建PreparedStatement
PS TMT=conn . prepare statement(SQL);
//5.获取查询结果
RS=PS TMT . execte query();
while(rs.next()){
int id=RS . getint( id );
string name=RS . getstring( name );
}
} catch(异常e) {
log.error(e.getMessage(),e);
}最后{
如果(rs!=null) {
RS . close();
}
if(pstmt!=null) {
pstmt . close();
}
如果(连接!=null) {
connection . close();
}
}在这个例子中,无论是ResultSet,还是PreparedStatement,或者Connection对象,在使用之后,都会调用close方法关闭资源。
这里温馨提醒:ResultSet,或者PreparedStatement,或者Connection object,这三者关闭资源的顺序不能颠倒,否则可能会出现异常。
5.使用池技术,我们都知道要从数据库中检查数据,首先要连接到数据库,获取连接资源。
如果您希望一个程序以多线程执行,您需要使用Thread类来创建线程。线程也是一种资源。
通常,数据库操作的过程如下:
为数据库操作创建连接关闭连接以及创建和关闭连接是非常耗时的操作。创建连接需要同时创建一些资源。当关闭一个连接时,这些资源需要被回收。
如果每次用户请求数据库时程序都需要创建和关闭连接,可能会浪费很多时间。
此外,它可能会导致过多的数据库连接。
我们都知道数据库中的最大连接数是有限的。以mysql为例,最大连接数为:100,但这个数字可以通过参数调整。
如果用户请求的连接数超过最大连接数,将会报告一个异常:连接过多。如果有新的请求,您会发现数据库变得不可用。
此时,您可以命令:
查看最大连接数。
然后传递命令:
手动修改最大连接数。
这种做法只能暂时缓解问题,但不是好办法,不能从根本上解决问题。
最大的问题是:数据库连接数可能会无限增长并失去控制。
这时,我们可以使用数据库连接池。
目前,Java开源数据库连接池包括:
DBCP:它是一个数据库连接池,依赖于Jakarta commons-pool对象池机制。
C3P0:是一个开源的JDBC连接池,它是用Hibernate发布在lib目录中的,包含了实现jdbc3和jdbc2扩展规范中描述的连接和语句池的DataSources对象。
Druid:阿里的Druid不仅仅是一个数据库连接池,还包含一个ProxyDriver,一系列内置的JDBC组件库和一个SQL解析器。
Proxool:是一个Java SQL驱动程序驱动程序,为其他选定的驱动程序提供连接池封装,可以方便地移植到现有代码中。
目前使用最多的数据库连接池是Druid。
版权归作者所有:来自博主的苦糖?原创作品请联系作者授权转载,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。