您的位置:首页 > 其它

杂记

2015-09-21 11:03 405 查看
首先说下高兴的事情,前两天拿到了第一张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拿到,加油
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: