项目经验总结-first
1. org.apache.commons.lang中StringUtils判空使用经验之谈
StringUtils.isEmpty(String str)
判断字符串str是否为空串且是否长度为0,即: str == null && str.length==0
- StringUtils.isBlank(String str)
判断字符串str是否为空串且是否长度为0且不由空白符号构成,具体有以下3中情况被过滤掉了:
str == null && str.length==0
""、" "、" "、" "等等(即空格字符)
"\t"、"\f"、"\r"、"\n" //制表符、换行符、换页符、回车符
2. 将字符串转换为整型或长整型(commons-lang)
NumberUtils.toInt(AppResource.resource.getString("SLEEP_INTERVAL_TIME"), 10);
可以避免获取到的值如果为空的话可以赋一个给定的默认值:10,不会抛异常
3. logback每个日志按照大小或时间切分以及规定多少个
<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="true">
<property name="logs" value="logs" />
<logger name="com.alibaba.jstorm.daemon.worker.metrics" level="ERROR"/>
<logger name="com.alibaba.jstorm.task.heartbeat" level="ERROR"/>
<logger name="com.alibaba.jstorm.daemon.worker.hearbeat" level="ERROR"/>
<logger name="com.alibaba.jstorm.metric" level="ERROR"/> <!--TRACE<DEBUG<INFO<WARN<ERROR-->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${logs}/datapreparation-ng.log</File>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{0} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logs}/datapreparation-ng.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender> <appender name="error"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<File>${logs}/datapreparation-ng_error.log</File>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{0} - %msg%n</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logs}/datapreparation-ng.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
</appender> <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{0} - %msg%n</pattern>
</encoder>
</appender> <root level="INFO">
<appender-ref ref="info"/>
<appender-ref ref="error"/>
<appender-ref ref="console"/>
</root>
</configuration>
4. StringBuilder内容如何清空
由于StringBuilder没有提供clear或empty方法,故需要采取其他的方法对其进行情况,具体我总结了有以下3中方式:
1)新生成一个,旧的由系统自动回收
2)使用delete
3)使用setLength
将三种方法循环1000万次进行压力测试:
Way1=9438ms
Way2=6281ms 最优
Way3=6469ms
看源代码如下图是way2即delete的实现方法:
我们再来看看way3的实现方法:
StringUtils.removeEnd(sortBuilder.toString(), ",")
或者在加逗号的时候判断一下是否需要添加:
Iterator<String> iterator = result.iterator(); //result可以是list、set
StringBuilder collectionSb = new StringBuilder();
int index = 0;
while (iterator.hasNext()) {
if (index > 0) {
collectionSb.append(",");
}
String collectionName = iterator.next();
collectionSb.append(collectionName);
index++;
}
6. 数字比较
不要使用x - y进行类似的比较,因为可能数很大且符号相反的数,这样可能会超出范围,建议使用以下的方式:
Integer.compare(int x, int y)
查看其源代码如下所示:
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
类似的有Double、Float等基本数据类型对应的对象。
7. 带逗号分隔的字符串转为List
方法 1:
利用JDK自带的Arrays类
String str = "a,b,c";
List<String> result = Arrays.asList(str.split(","));
方法 2:
利用Guava的Splitter
String str = "a, b, c";
List<String> result = Splitter.on(",").trimResults().splitToList(str);
方法 3:
利用Apache Commons的StringUtils (只是用了split)
String str = "a,b,c";
List<String> result = Arrays.asList(StringUtils.split(str,","));
方法 4:
利用Spring Framework的StringUtils
String str = "a,b,c";
List<String> str = Arrays.asList(StringUtils.commaDelimitedListToStringArray(str));
8. List转换为带逗号分隔符的字符串
方法 1:
利用JDK (好像没有很好的方法,需要一步一步实现)
NA
方法 2:
利用Guava的Joiner
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String str = Joiner.on(",").join(list);
方法 3:
利用Apache Commons的StringUtils
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String str = StringUtils.join(list.toArray(), ",");
方法 4:
利用Spring Framework的StringUtils
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
String str = StringUtils.collectionToDelimitedString(list, ",");
比较下来,我的观点就是Guava库更灵活,适用面更广。项目中如果没有引入Guava的话,那就加上它。
9. 使用数组一定不要使用二维数组
作为软件开发人员我们必须知道,以为数组的访问速度明显比多维数组的访问速度快。因此,在性能敏感的系统中要使用二位数组的,可以尝试通过可靠的算法,将二维数组转为一维数组,以提高系统的响应速度。
1o. 展开循环
展开循环时一种在极端情况下使用的优化手段,因为展开循环很可能会影响代码的可读性和可维护性,而这两者对系统来说也是极为重要的。但是,当性能问题成为系统的主要矛盾时,展开循环绝对是一种值得尝试的技术,实例测试代码如下:
一个普通的循环代码如下:
//循环1000万次
int[] array = new int[9999999];
for(int i = 0; i < 9999999; i++) {
array[i] = i;
}
展开循环,类似于一下格式:
int[] array = new int[9999999];
for(int i = 0; i < 9999999; i+=3) {
array[i] = i;
array[i+1] = i + 1;
array[i+2] = i + 2;
}
以上两端代码功能完全相同,但第二段代码进行了循环展开的优化,在一个循环体内处理了源代码段中的3个循环逻辑。运行以上两段代码,第一段代码相对耗时:94ms,第二段代码相对耗时:31ms,可见展开循环后,减少循环次数,对提升系统性能很有帮助。
11. 静态方法替代实例方法
使用static关键字描述的方法为静态方法。在java中,由于实例方法需要维护一张类似虚拟函数表的结构,以实现对多态的支持。与静态方法相比,实例方法的调用需要更多的资源,因此,对于一些常用的工具类方法,没有对其进行重载的必要,那么将它们声明为static,便可以加速方法的调用。
public static void staticMethod() {
System.out.println("staticMethod call");
} public void instanceMethod() {
System.out.println("instanceMethod call");
} @Test
public void test() {
int CIRCLE = 100000000;//调用1亿次
long start = System.currentTimeMillis();
for (int i = 0; i < CIRCLE; i++) {
staticMethod();
}
System.out.println(String.format("staticMethod:%d ms", (System.currentTimeMillis() - start))); start = System.currentTimeMillis();
for (int i = 0; i < CIRCLE; i++) {
instanceMethod();
}
System.out.println(String.format("instanceMethod:%d ms", (System.currentTimeMillis() - start)));
}
测试代码中统计两个方法调用若干次后的耗时,程序输出如下:
staticMethod:85 ms
instanceMethod:155 ms
可以看到,就方法调用速度而言,静态方法明显快于实例方法。其实使用static方法实现,这样不仅可以加快函数调用的速度,同时,调用static方法也不需要生成类的实例,比调用实例方法更为方便、易用。
12. 使用Buffer进行I/O操作
除NIO外,使用Java进行I/O操作有两种基本方式:
1. 使用基于InputStream 和 OutputStream的方式;
2. 使用Writer 和 Reader。
无论使用哪种方式进行文件I/O,如果能合理地使用缓冲,都能提高I/O的性能,如下图显示了可与InputStream、OutputStream、Writer 和 Reader 配套使用的缓冲组件:
使用缓冲组件对文件 I/O 进行包装,可以有效提升文件 I/O 的性能,以BufferedReader为例,BufferedReader会一次性从物理流中读取8k(默认数值,可以设置)字节内容到内存,如果外界有请求,就会到这里存取,如果内存里没有才到物理流里再去读。即使读,也是再8k。如果不使用BufferedReader而直接读物理流,是按字节来读,对物理流的每次读取,都有IO操作。IO操作是最耗费时间的。BufferedReader就是减少了大量IO操作,而为你节省了时间。简单的说,一次IO操作,读取一个字节也是读取,读取8k个字节也是读取,两者花费时间相差不多。而一次IO的来回操作却要耗费大量时间。
好比是一辆大型汽车(设装100人),要去车站接人到公司,接一个人也是接,接100个人也是接,而时间一样。显然,接100个人最划算。
Buffered就是一次8k个字节(100个人)
下面是一段直接使用 InputStream 和 OutputStream 进行文件读写的样例:
private static final int count = 10000;
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("testFile.txt")));
for (int i = 0; i < count; i++) {
dos.writeBytes(String.valueOf(i) + "\r\n"); //写入数据
}
dos.close();
System.out.println(String.format("testStream write file cost time: %dms", (System.currentTimeMillis() - start))); start = System.currentTimeMillis();
DataInputStream dis = new DataInputStream(new FileInputStream(new File("testFile.txt")));
while (dis.readLine() != null) ; //读取数据
dis.close();
System.out.println(String.format("testStream read file cost time: %dms", (System.currentTimeMillis() - start)));
}
与之对应的一段使用缓冲的代码如下:
private static final int count = 10000;
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("testFile.txt"))));
for (int i = 0; i < count; i++) {
dos.writeBytes(String.valueOf(i) + "\r\n"); //写入数据
}
dos.close();
System.out.println(String.format("testBufferedStream write file cost time: %dms", (System.currentTimeMillis() - start))); start = System.currentTimeMillis();
DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("testFile.txt"))));
while (dis.readLine() != null) ; //读取数据
dis.close();
System.out.println(String.format("testBufferedStream read file cost time: %dms", (System.currentTimeMillis() - start)));
}
运行两段代码,输出结果如下:
testStream write file cost time: 657ms
testStream read file cost time: 125ms
testBufferedStream write file cost time: 0ms
testBufferedStream read file cost time: 15ms
很明显使用缓冲的代码无论在读取还是写入文件上,性能都有了数量级的提升。使用Writer 和 Reader 有类型的效果。下面使用 FileWriter 和 FileReader 进行文件读写操作:
private static final int count = 10000;
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
FileWriter fw = new FileWriter(new File("testFile.txt"));
for (int i = 0; i < count; i++) {
fw.write(String.valueOf(i) + "\r\n"); //写入数据
}
fw.close();
System.out.println(String.format("testFileWriter write file cost time: %dms", (System.currentTimeMillis() - start))); start = System.currentTimeMillis();
FileReader fr = new FileReader(new File("testFile.txt"));
while (fr.read() != -1) ;
fr.close();
System.out.println(String.format("testFileReader read file cost time: %dms", (System.currentTimeMillis() - start)));
}
与之对应使用缓冲的实现方式如下:
private static final int count = 10000; public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("testFile.txt")));
for (int i = 0; i < count; i++) {
bw.write(String.valueOf(i) + "\r\n"); //写入数据
}
bw.close();
System.out.println(String.format("testBufferedWriter write file cost time: %dms", (System.currentTimeMillis() - start))); start = System.currentTimeMillis();
BufferedReader br = new BufferedReader(new FileReader(new File("testFile.txt")));
while (br.read() != -1) ;
br.close();
System.out.println(String.format("testBufferedReader read file cost time: %dms", (System.currentTimeMillis() - start)));
}
运行两段代码,输出结果如下:
testFileWriter write file cost time: 94ms
testFileReader read file cost time: 125ms
testBufferedWriter write file cost time: 63ms
testBufferedReader read file cost time: 62ms
总结:由测试结果可知,使用缓冲后,无论是 FileReader 还是 FileWriter 的性能都有较为明显的提升。
项目经验总结-first的更多相关文章
- 《项目经验》--通过js获取前台数据向一般处理程序传递Json数据,并解析Json数据,将前台传来的Json数据写入数据库表中
先看一下我要实现的功能界面: 这个界面的功能在图中已有展现,课程分配(教师教授哪门课程)在之前的页面中已做好.这个页面主要实现的是授课,即给老师教授的课程分配学生.此页面实现功能的步骤已在页面 ...
- Java项目经验——程序员成长的关键(转载)
Java就是用来做项目的!Java的主要应用领域就是企业级的项目开发!要想从事企业级的项目开发,你必须掌握如下要点:1.掌握项目开发的基本步骤2.具备极强的面向对象的分析与设计技巧3.掌握用例驱动.以 ...
- Java项目经验
Java项目经验 转自CSDN. Java就是用来做项目的!Java的主要应用领域就是企业级的项目开发!要想从事企业级的项目开发,你必须掌握如下要点:1.掌握项目开发的基本步骤2.具备极强的面向对象的 ...
- OSG项目经验2<在场景中添加文字面版>
添加文字版需要用到osg的三个名字空间: osgText::Text,这个类用来添加文字和设置文字的一些属性: ...
- 最近面试java后端开发的感受:如果就以平时项目经验来面试,通过估计很难——再论面试前的准备
在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间.我的标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架,我相信其它公司招初级开发时,应该也照着这个标准来面 ...
- java程序员面试交流项目经验
粘贴自:https://blog.csdn.net/wangyuxuan_java/article/details/8778211 1:请你介绍一下你自己 这是面试官常问的问题.一般人回答这个问题过于 ...
- 项目经验分享[转自min.jiang]
最近三个月,我非常荣幸的做为TeamLeader带领几个小组成员做了一个国外项目,这里想为大家分享一些小经验,尽管我佣有六年多的项目经验,但我一直的方向是架构师.大家知道架构师一般情况是偏向技 ...
- Georgia Tech Online Master of Science in Computer Science 项目经验分享
Georgia Tech Online Master of Science in Computer Science 项目经验分享 Posted on 2014/04/22 项目关键词:工科名校,计算机 ...
- IdentityServer4系列之中文文档及实际项目经验分享
0.前言 原文:http://docs.identityserver.io/en/release/声明: 1.目录一至五章节根据IdentityServer英文文档翻译而来,有些内容会根据自己的理解来 ...
- java面试项目经验:框架及应用
Java项目经验 Java就是用来做项目的!Java的主要应用领域就是企业级的项目开发!要想从事企业级的项目开发,你必须掌握如下要点:1.掌握项目开发的基本步骤2.具备极强的面向对象的分析与设计技巧3 ...
随机推荐
- 20180711-统计PDB中的蛋白质种类、膜蛋白文件个数及信息等
20180710完成这份工作.简单,但是完成了还是很开心.在我尝试如何使用pickle保存数据后,尝试保存PDB文件中“HEADER”中的信息.文件均保存于实验室服务器(97.73.198.168)/ ...
- SQLyog的基本使用
[简介] SQLyog是mysql数据库的客户端软件 [基本使用] 1.连接mysql数据库 2.SQLyog的页面使用介绍 3.基本的数据库命令 1) use命令 切换数据库 2) unsigned ...
- EF三种编程方式详细图文教程(C#+EF)之Model First
Model First Model First我们称之为“模型优先”,这里的模型指的是“ADO.NET Entity Framework Data Model”,此时你的应用并没有设计相关数据库,在V ...
- Chapter 11 软件演化
软件一直在不断地演化发展,人们通常通过软件维护和软件再工程解决软件的缺陷.软件维护可以分为改正性维护.适应性维护和完善性维护几种类型.软件维护受开发过程影响大.软件维护困难大.软件维护成本高.软件维护 ...
- C# Linq找不到行或已更改
前段时间工作中的一个新需求,有机会用到了Linq to SQL.使用后的第一感觉,就是方便很多,也为整个项目节约了一大把的开发时间,甚至代码量也少了很多.不过在程序的实际运行中,始终会遇到一些莫名其妙 ...
- Internet History, Technology and Security (Week7)
Week7 With reliable "pipes" available from the Transport layer, we can build applications ...
- 1003 我要通过!| PAT (Basic Level) Practice
1003 我要通过! (20 分) "答案正确"是自动判题系统给出的最令人欢喜的回复.本题属于 PAT 的"答案正确"大派送 -- 只要读入的字符串满足下列条件 ...
- Java中DAO的实现
J2EE 开发人员使用数据访问对象(Data Access Object DAO)设计模式,以便将低级别的数据访问逻辑与高级别的业务逻辑分离.实现 DAO 模式涉及比编写数据访问代码更多的内容.在本文 ...
- grunt入门讲解7:项目脚手架grunt-init
grunt-init是一个用于自动创建项目脚手架的工具.它会基于当前工作环境和你给出的一些配置选项构建一个完整的目录结构.至于其所生成的具体文件和内容,依赖于你所选择的模版和构建过程中你对具体信息所给 ...
- 关于JEE web项目 Servlet中 “/” 的解释 ;
1.关于"/" 可以代表web应用的根目录,也可以代表站点的根目录: 1>如果交给浏览器解析,则代表web站点的根目录,如果交给web服务器解析则代表项目的根目录: 2> ...