zoukankan      html  css  js  c++  java
  • 项目经验总结-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中情况被过滤掉了:

      1. str == null  &&  str.length==0

      2. ""、" "、"  "、"     "等等(即空格字符)

      3. " "、"f"、" "、" "    //制表符、换行符、换页符、回车符    

    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的实现方法:

     
     
    5. 去掉字符串最后一个字符
    StringUtils.removeEnd(sortBuilder.toString(), ",")
    或者在加逗号的时候判断一下是否需要添加:
     1 Iterator<String> iterator = result.iterator();    //result可以是list、set
     2 StringBuilder collectionSb = new StringBuilder();
     3 int index = 0;
     4 while (iterator.hasNext()) {
     5     if (index > 0) {
     6         collectionSb.append(",");
     7     }
     8     String collectionName = iterator.next();
     9     collectionSb.append(collectionName);
    10     index++;
    11 }

    6. 数字比较

      不要使用x - y进行类似的比较,因为可能数很大且符号相反的数,这样可能会超出范围,建议使用以下的方式:

      Integer.compare(int x, int y)

      查看其源代码如下所示:

    1 public static int compare(int x, int y) {
    2     return (x < y) ? -1 : ((x == y) ? 0 : 1);
    3 }

      类似的有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,便可以加速方法的调用。

     1 public static void staticMethod() {
     2     System.out.println("staticMethod call");
     3 }
     4     
     5 public void instanceMethod() {
     6     System.out.println("instanceMethod call");
     7 }
     8 
     9 @Test
    10 public void test() {
    11     int CIRCLE = 100000000;//调用1亿次
    12     long start = System.currentTimeMillis();
    13     for (int i = 0; i < CIRCLE; i++) {
    14         staticMethod();
    15     }
    16     System.out.println(String.format("staticMethod:%d ms", (System.currentTimeMillis() - start)));
    17         
    18     start = System.currentTimeMillis();
    19     for (int i = 0; i < CIRCLE; i++) {
    20         instanceMethod();
    21     }
    22     System.out.println(String.format("instanceMethod:%d ms", (System.currentTimeMillis() - start)));
    23 }

    测试代码中统计两个方法调用若干次后的耗时,程序输出如下:

    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 进行文件读写的样例:

     1 private static final int count = 10000;
     2 public static void main(String[] args) throws IOException {
     3     long start = System.currentTimeMillis();
     4     DataOutputStream dos = new DataOutputStream(new FileOutputStream(new File("testFile.txt")));
     5     for (int i = 0; i < count; i++) {
     6         dos.writeBytes(String.valueOf(i) + "
    ");    //写入数据
     7     }
     8     dos.close();
     9     System.out.println(String.format("testStream write file cost time: %dms", (System.currentTimeMillis() - start)));
    10     
    11     start = System.currentTimeMillis();
    12     DataInputStream dis = new DataInputStream(new FileInputStream(new File("testFile.txt")));
    13     while (dis.readLine() != null) ;    //读取数据
    14     dis.close();
    15     System.out.println(String.format("testStream read file cost time: %dms", (System.currentTimeMillis() - start)));
    16 }

    与之对应的一段使用缓冲的代码如下:

     1 private static final int count = 10000;
     2 public static void main(String[] args) throws IOException {
     3     long start = System.currentTimeMillis();
     4     DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("testFile.txt"))));
     5     for (int i = 0; i < count; i++) {
     6         dos.writeBytes(String.valueOf(i) + "
    ");    //写入数据
     7     }
     8     dos.close();
     9     System.out.println(String.format("testBufferedStream write file cost time: %dms", (System.currentTimeMillis() - start)));
    10     
    11     start = System.currentTimeMillis();
    12     DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("testFile.txt"))));
    13     while (dis.readLine() != null) ;    //读取数据
    14     dis.close();
    15     System.out.println(String.format("testBufferedStream read file cost time: %dms", (System.currentTimeMillis() - start)));
    16 }

    运行两段代码,输出结果如下:

    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) + "
    ");    //写入数据
            }
            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) + "
    ");    //写入数据
            }
            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 的性能都有较为明显的提升。

      

  • 相关阅读:
    setCapture 适用范围
    移动web页面自动探测电话号码
    WEB页面JS实现一键拨号的电话拨打功能
    highcharts动态删除标示区
    【你不知道的JavaScript
    【你不知道的JavaScript
    【JavaScipt高级程序设计 第4版】第5章笔记 日期格式
    【JavaScipt高级程序设计 第4版】第6章笔记 Map Set
    【JavaScipt高级程序设计 第4版】第6章笔记 Array 集合引用类型
    【JavaScipt高级程序设计 第4版】第4章笔记
  • 原文地址:https://www.cnblogs.com/liang1101/p/6383235.html
Copyright © 2011-2022 走看看