• 杂记


    首先说下高兴的事情,前两天拿到了第一张offer了,不用担心自己找不到工作了。但是这个工作是在深圳,本人是武汉人,还是挺不方便的,所以还在继续的找工作中

    不高兴的事情,今天有场面试,要带上成绩单,于是去学工办去打印成绩单,靠,那女的 的态度真心让人不爽,应该是个研究生,郁闷。。。

    OK,开始说技术把。

    这些天一直在各种宣讲会,笔试面试,各种奔波,关键是我们这个校区太偏,所以基本一天都耗在公交上了,因此这几天学的东西有限:

    1.自优化的代码:

    这里所谓的优化,并不是对整个项目的优化,而是对自己写的代码进行优化,知道怎么写效率会高些,主要针对字符串

    (1)就是String的split方法 对比StringTokenizer类,都是用指定的分隔符分解String,但是在效率上有差异

      首先给出测试代码:

        @Test
        public void test1() {
             String orgStr = null;
             StringBuffer sb = new StringBuffer();
             for(int i=0;i<100000;i++){
             sb.append(i);
             sb.append(",");
             }
             orgStr = sb.toString();
             long start = System.currentTimeMillis();
             String[] strs = orgStr.split(",");
             int count = 0;
             for(String s:strs) {
                 count++;
             }
             System.out.println(count);
             long end = System.currentTimeMillis();
             System.out.println(end-start);
             
             start = System.currentTimeMillis();
             StringTokenizer st = new StringTokenizer(orgStr,",");
             count = 0;
             while(st.hasMoreTokens()) {
                 String str = st.nextToken();
                 count++;
             }
             System.out.println(count);
             end = System.currentTimeMillis();
             System.out.println(end-start);
        }

    运行后的测试结果为

    100000
    38
    100000
    21

    可以看到,当String很长,而且分解得到的String很多的时候,StringTokenizer的效率要高点。

    但是 : 用StringTokenizer 明显比直接用split方法要复杂一些

    因此,在不是很要求效率的情况下,还是使用split方法,这个代码也看起来清晰一些,毕竟有时候代码的清晰比效率更重要一些

    (2)字符串的连接

    这个相信大家都知道,String是final的,连接字符串很多的话最好有StringBuilder(单线程),或者StringBuffer(多线程)

    然而我最近在一篇文章中看到了还可以用String的 concat方法来连接字符串,下面对比下这些连接方式的快慢

        @Test
        public void testStringConcat () {
             String str = null;
             String result = "";
             
             long start = System.currentTimeMillis();
             for(int i=0;i<10000;i++){
             str = str + i;
             }
             long end = System.currentTimeMillis();
             System.out.println(end-start);
             
             start = System.currentTimeMillis();
             for(int i=0;i<10000;i++){
             result = result.concat(String.valueOf(i));
             }
             end = System.currentTimeMillis();
             System.out.println(end-start);
             
             start = System.currentTimeMillis();
             StringBuilder sb = new StringBuilder();
             for(int i=0;i<10000;i++){
             sb.append(i);
             }
             end = System.currentTimeMillis();
             System.out.println(end-start);
        }

    最后运行的结果为:

    219
    87
    0

    很明显,直接用+连接字符串耗时更长,但是按道理说这样写的代码编译器会帮我们进行优化,怎么还是耗这么长时间呢?按照那篇博客上看到的,是因为编译器不够智能,虽然会使用StringBuilder(StringBuffer)来连接,但是是每一次都建立一个新的StringBuilder(~)对象,我不知道是不是这样的

    然后concat方法比直接用+效率要高,StringBuilder效率是最高的。

    所以,我感觉,在想优化的地方,不要怕麻烦,使用StringBuilder或者StringBuffer,连接次数很少的地方还是使用+,感觉使用concat方法挺麻烦的.

    (3)对局部变量的操作比全局变量的效率要高

    测试代码:

        public static int b = 0;
        @Test
        public void testVariableCompare () {
             int a = 0;
             long starttime = System.currentTimeMillis();
             for(int i=0;i<1000000;i++){
             a++;//在函数体内定义局部变量
             }
             System.out.println(System.currentTimeMillis() - starttime);
             
             starttime = System.currentTimeMillis();
             for(int i=0;i<1000000;i++){
             b++;//在函数体内定义局部变量
             }
             System.out.println(System.currentTimeMillis() - starttime);
        }

    运行结果:

    2
    3

    从结果确实可以看出来这点,但是好像差别不是很大,但是还是可以注意一下这个点,在不破坏代码的可读性和清晰的时候,尽可能的使用局部变量把,我好像想到了effective java里面的一个建议,是类和成员的可访问性最小化,就是说如果一个变量只在for循环里面用到的话,就没必要在外面定义它等等。。。

    (4)位运算优先

    这个是肯定的,cpu是天然支持位运算的,中间不用任何的转化,测试代码

        @Test
        public void testOperator() {
             long start = System.currentTimeMillis();
             long a=1000;
             for(int i=0;i<10000000;i++){
             a*=2;
             a/=2;
             }
             System.out.println(a);
             System.out.println(System.currentTimeMillis() - start);
             start = System.currentTimeMillis();
             for(int i=0;i<10000000;i++){
             a<<=1;
             a>>=1;
             }
             System.out.println(a);
             System.out.println(System.currentTimeMillis() - start);
        }

    结果如下:

    1000
    22
    1000
    5

    很明显,位运算比*,/运算快了不止一点,所以之前在List源码里面看到扩展数组的时候就是用的位运算

    OK,自由化就看了这么多,接下来的内容是java8的更新

    2.java8

    在之前的博文里面已经写过java8方面的内容了,现在写的是之前没有写到的,主要是java.util.stream包里面的的内容

    之前确实看到util里面多了个stream,但是不知道是干什么的,现在看了一篇博客后,会简单的使用了

    使用如下:

        @Test
        public void test() {
            List<String> list = new ArrayList<>();
            list.addAll(Arrays.asList("first","second","third"));
            long count = list.stream().filter(data -> !data.equals("first")).count();
            System.out.println(count);
            
            List<String> list1 = list.stream().map(data -> data + data).collect(Collectors.toList());
            list1.forEach(System.out::println);
            
            List<String> list2 = list.stream().map(data -> data.toUpperCase()).collect(Collectors.toList());
            list2.forEach(System.out::println);
            
        }

    得到的结果:

    2
    firstfirst
    secondsecond
    thirdthird
    FIRST
    SECOND

    来分析下这段代码,现在每个List,Set,Map.好像都有一个stream方法,这个方法会建立一个流(注意,这个流跟inputstream没关系,也不一样),然后就能够使用里面的一些方法了,比如上面使用到的filter 可以过滤掉容器里面的部分内容,count,得到最后的数量,当然还有很多方法,大家可以去看看和尝试下,感觉stream和lambda表达式一起使用挺方便的,

    可以通过stream来新建一个List,

    最后,增强的forEach方法,是遍历的一个方法,可以和lambda表达式一起使用,可以代替for  in 循环

    关于stream,我就讲到这里了,里面还有很多东西,以后再去看。

    3.关于guava,

    之前一直想学习使用guava的,但是发现里面的部分内容,在jdk里面直接实现了,就放弃了学习。

    最近发现里面的collection这个里面的东西还挺有趣的,所以又看了下,主要是collection

    (1)首先是不可变集合,jdk里面可以通过Collection.unmodifiable*方法来得到一个不可变集合,但是这个不可变集合并非是真的不可变的,对得到的集合进行操作的话,确实会抛出异常,但是如果对原集合进行操作的话,也会将得到的不可变集合的内容给改动

    测试代码如下:

        @Test
        public void testOld() {
             Set<String> set = new HashSet<String>(Arrays.asList(new String[]{"RED", "GREEN"})); 
             Set<String> unmodifiableSet = Collections.unmodifiableSet(set);
             set.forEach(data -> {
                 System.out.println(data);
             });
             unmodifiableSet.forEach(data -> {
                 System.out.println(data);
             });
             
             set.remove("RED");
             System.out.println("---after remove---");
             
             set.forEach(data -> {
                 System.out.println(data);
             });
             unmodifiableSet.forEach(data -> {
                 System.out.println(data);
             });
        }

    测试结果如下:

    RED
    GREEN
    RED
    GREEN
    ---after remove---
    GREEN
    GREEN

    可以看到,我只将set里面的RED删除了,但是unmodifiableSet里面的内容也删除了。

    看看guava里面的immutableSet:

        @Test
        public void testGuavaImmutableSet() {
            Set<String> set = new HashSet<String>(Arrays.asList(new String[]{"RED", "GREEN"})); 
            ImmutableSet<String> immutableSet = ImmutableSet.copyOf(set);
            
            set.forEach(data -> {
                 System.out.println(data);
             });
            immutableSet.forEach(data -> {
                System.out.println(data);
            });
            
            set.remove("RED");
            System.out.println("---after remove---");
            
            set.forEach(data -> {
                 System.out.println(data);
             });
            immutableSet.forEach(data -> {
                System.out.println(data);
            });
        }

    测试结果如下:

    RED
    GREEN
    RED
    GREEN
    ---after remove---
    GREEN
    RED
    GREEN

    就没有这个问题,从方法名上也大概可以看到,jdk里面的方法,估计是将原来的set包在unmodifiableSet里面去了,但是guava是复制了一份内容保存,当然这只是猜测,没有去看源码,因为eclipse居然看不到源码,还是idea好

    然后里面还有multiSet 可以插入重复值,MultiMap 一个key可以对应多个value,biMap 一个key,对应一个value,并且一个value,对应一个key,也就是一一对应。这些集合的代码就不复制出来了,不然又是全篇都是代码了。

    OK,今天就写到这里把,之后几天争取再拿几张offer,争取将华为的offer拿到,加油

  • 相关阅读:
    日志配置
    Mybaties核心配置文件
    配置3
    写了两个数据获得方式----费劲周折
    applicationContext
    配置2
    Django-缓存的配置
    RabbitMQ的工作模式
    centos下保留python2安装python3
    python位运算
  • 原文地址:https://www.cnblogs.com/luolei/p/4825537.html
Copyright © 2020-2023  润新知