一、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));

    }