一、Java Stream流操作性能测试
1、reduce测试
普通reduce合并字符串测试
public static void method() {
int capacity = 10000000;
List<String> list = new ArrayList<>(capacity);
for (int i = 0; i < capacity; i++) {
list.add("name" + i);
}
long start = System.currentTimeMillis();
System.out.println(list.stream().reduce((u, v) -> u + "," + v).orElse(""));
System.out.println("consume time = " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < capacity; i++) {
sb.append(list.get(i) + ",");
}
System.out.println(sb.toString().substring(0, sb.length() - 1));
System.out.println("consume time = " + (System.currentTimeMillis() - start));
}
注:使用reduce 进行字符串合并时,消耗的秒数万极已经是秒级,到十万级及以上需消耗大量时间不能在正常编码中使用。
如果使用StringBuild进行append拼接在百万级以内都是毫秒级,百万级以上才是秒级,最大测试千万需要大概10秒(4核8G)。
分析原因:两者的差距大主要是reduce中使用的是普通的string字符串加操作,性能和StringBuild的append差距比较大,因为字符串的+操作也是需要不断的new出新的字符串对象,消耗时间。如果使用String进行累加的话性能和reduce几乎一样。
结论:主要是在字符串拼接时千万不要使用String进行累加,需要使用StringBuild的append方法进行字符串拼接(笑哭表情)。
reduce处理不能出现最后结果为null的情况,否则会报错
public static void main(String[] args) {
List<String> list = Arrays.asList(null, null, null);
StringBuilder stringBuilder = new StringBuilder();
for (String s : list) {
if (stringBuilder.length() > 0) {
stringBuilder.append("," + s);
} else {
stringBuilder.append(s);
}
}
String name = list.stream().map(u -> {
if ("2".equals(u)) {
return null;
} else {
return u;
}
}).reduce((x, v) -> {
if (StringUtils.isEmpty(x)) {
if (StringUtils.isEmpty(v)) {
//如果返回null 如果所有元素都为null到最后reduce完后会出现报错 可能是返回为null导致后续处理失败
return "";
} else {
return v;
}
} else {
if (StringUtils.isEmpty(v)) {
return x;
} else {
return x + "," + v;
}
}
}).orElse(null);
System.out.println(StringUtils.isEmpty(name) ? null : name);
System.out.println(stringBuilder.toString());
System.out.println("=============");
list.stream().map(u -> u).forEach(System.out::println);
System.out.println(SIMPLE_DATE_FORMAT.format(new Date()));
}
2、List集合去重或则去null
使用stream distinct 去重,使用removeAll(Collections.singletonList(null))去null
public static void main(String[] args) {
List<String> name = Arrays.asList("1", "2", "3");
List<String> things = name.stream().map(u -> {
if ("3".equals(u)) {
return u;
} else {
return null;
}
}).distinct().collect(Collectors.toList()) ;
things.removeAll(Collections.singletonList(null));
System.out.println(things.size());
}
或则可以通过把List转成Set来去重(其实Set就是HashMap的key值集合)
并且TreeSet实现了自然排序(从大到小)
public static void main(String[] args) {
List<String> name = Arrays.asList("2", "1", "3", "3", null, null);
//这种方式默认返回的Set是HashSet,其中只有TreeSet才能排序
Set<String> strings = name.stream().collect(Collectors.toSet());
//set也可以移除null
strings.removeAll(Collections.singletonList(null));
strings = new HashSet<>(strings);
System.out.println(strings);
// output [null, 1, 2, 3]
}
集合的有序无序性
先插的位置在前,后插的位置在后,则为有序,反之无序
而大家容易混淆的就是排序,排序是指集合内的元素是否按照升序或降序来排序
实现了List接口的集合类全部有序,如ArrayList、LinkedList
实现了Set接口的集合类中,HashSet无序,TreeSet排序
实现了Map接口的集合类中,HashMap无序,TreeMap排序
3、字符串操作
字符串特殊字符拼接
public static void main(String[] args) {
//内部也是使用 StringBuilder 来进行字符拼接
StringJoiner stringJoiner = new StringJoiner(",","-","-");
stringJoiner.add("name");
stringJoiner.add("family");
System.out.println(stringJoiner);
//output name,family
//output -name,family- 带前缀后缀
//String 静态方法join内部使用StringJoin来进行字符串拼接
String[] name = {"tome", "jack"};
System.out.println(String.join(",", name));
//output tome,jack
//Joiner万级字符串基本达到秒级和字符串加操作性能损耗相同 大量字符串拼接不能使用此方法
long start = System.currentTimeMillis();
String fin = "name";
for (int i = 0; i < 10000; i++) {
fin = Joiner.on(",").skipNulls().join(fin, "name" + i);
}
System.out.println(fin);
System.out.println("consume time = " + (System.currentTimeMillis() - start));
}