杂记

首先说下高兴的事情,前两天拿到了第一张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拿到,加油

posted on 2015-09-21 11:03  头机器人  阅读(201)  评论(0编辑  收藏  举报

导航