Java8语法新特性总结(并行流一定快?)

Lambda表达式

()->{}

通过接口函数来简化匿名内部类的写法,如下。

/**<h1>无参写法</h1>*/
//jdk7 写法
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("runnablesTest");
    }
}).start();
//lambda 表达式写法
new Thread(() -> {
    System.out.println("runnableTest");
}).start();

/**<h1>带参写法</h1>*/
List<String> strings = Arrays.asList("a", "b", "c");
//jdk7
Collections.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        if (o1.length() > o2.length()) {
            return 1;
        }
        return 0;
    }
});
//lambda
Collections.sort(strings, (s1, s2) -> s1.length() > s2.length() ? 1 : 0);

可见通过lambda的写法,不但省去了匿名内部类定义,连参数的类型都可直接省略。而真正帮我们完成类型定义是在编译阶段,javac的类型推断机制,赋予真正的类型,从而无需显式的声明出类型。并非入其他弱类型语言无需定义变量类型。

:: 方法引用
ArrayList<java.lang.String> strs = new ArrayList<>();
strs.add("aaa");
strs.add("bbb");
strs.add("ccc");

List<String> collect = strs.stream().map(str -> str.toUpperCase()).collect(Collectors.toList());

ArrayList<String> collect1 = strs.stream().map(String::toUpperCase).collect(Collectors.toCollection(ArrayList::new));

Collection新特性

foreach:对集合进行遍历
List<String> list = new ArrayList<>(Arrays.asList("aaa", "bbb", "ccc"));
list.forEach(str -> {
    System.out.println(str);
});
removeIf:删除满足条件的元素(函数返回值为boolean)
list.removeIf(str -> str.equals("aaa"));
replaceAll:替换元素(返回值为Object)
list.replaceAll(String :: toUpperCase);
sort:排序
list.sort((s1,s2)->s1.length()>s2.length()?0:1);

Map新特性

forEach:循环遍历元素
Map<String, String> map = new HashMap<>();
map.put("1","aaa");
map.put("2","bbb");
map.put("3","ccc");

map.forEach((k,v)->{
    System.out.println("key:"+k+" Value:"+v);
});

getOrDefault:根据key获取值,若无则放回默认值
String aDefault = map.getOrDefault("11", "default");
putIfAbsent:若对应key值为null,则设值
map.putIfAbsent("1","ccc");
remove:移除值
//移除key为 "2" 的值
map.remove("2");
//移除key为 "3" ,且值为 "ccc" 对应记录
map.remove("3","ccc");
replace:替换值
//替换值
map.replace("1","AAA");
//替换值 若旧值为ccc
map.replace("2","ccc","BBB");
replaceAll:替换所有
map.replaceAll((k,v)->v.toUpperCase());
merge:若对应key值为null则设值,反之则将二值进行自定义操作
map.merge("1","qqq",(v1,v2)->v1+v2);
compute:将值进行一系列操作再设值给key
//若 key "1" 对应的值为 "aaa" 这删除该值, 否者则将key"1" 设值为 "qqq"
map.compute("1", (k, v) -> v == "aaa" ? null : "qqq");
computeIfAbsent:若key值为null,则执行后面的操作,否则不执行
map.computeIfAbsent("11",v->v.toUpperCase());
computeIfPresent:与computeIfAbsent相反,若其key值存在则执行后续操作
map.computeIfPresent("1",(k,v)->v.toUpperCase());

Stream

基本四种Strean:IntStream、LongStream、DoubleStream、Stream

操作分类:

  • 中间操作:对元素就行过滤、拼接等生成一系列操作,生成新的stream(concat()、distinct()、filter()、flatMap()、limit()、map()、peek()、skip()、sorted()、parallel()、sequential()、unordered())
  • 结束操作:转为指定的数据类型返回(allmatch()、 allMatch() 、anyMatch()、collect()、count()、findAny()、findFirst()、forEach()、forEachOrdered()、max()、min()、noneMatch()、reduce()、toArray())
foreach:遍历集合
Stream<String> aaa = Stream.of("aaa", "bbb", "ccc");
aaa.forEach(System.out::println);
filer:数据过滤,操作函数返回boolean类型,剔除不符合条件元素
stream.filter(i->"aaa".equals(i)).forEach(System.out::println);
distinct:去重,执行后重复元素将被剔除
stream.distinct().forEach(System.out::println);
sorted:排序,操作函数返回执行前后元素个数不变
stream.sorted((s1,s2)->s1.compareTo(s2)).forEach(System.out::println);
map:对元素自定义操作,操作前后元素个数不变(即将每个输入值,生成一个结果值)
stream.map(String::toUpperCase).forEach(System.out::println);
flatmap:将多个集合合并为一个(消耗一个值生成任意数量的值)
Stream<List<Integer>> listStream = Stream.of(Arrays.asList(1,2), Arrays.asList(3, 4, 5));
listStream.flatMap(list->list.stream()).forEach(System.out::println);
reduce:统计(找最大、最小、求和等等)
String maxLengthStr = stream.reduce((s1, s2) -> s1.length() > s2.length() ? s1 : s2).get();

Integer sumOfLength = stream.reduce(0, (sum, str) -> sum += str.length(), (s1, s2) -> s1 + s2);
Collect:将返回结果转为其他集合对象
//收集器将结果转为其他容器
ArrayList<Object> collect = stream.collect(ArrayList::new, //目标容器
                                           ArrayList::add, //元素如何添加到容器
                                           ArrayList::addAll); //多个元素如何合并

//使用收集器的工具类转换
List<String> list = stream.filter(str -> str.startsWith("a")).collect(toList());

Set<String> set = stream.filter(str -> str.startsWith("a")).collect(toSet());

//转map 
//toMap() 
Map<String, Integer> map = stream.distinct().collect(toMap(Function.identity(), String::length));
//patitioningBy() 适用于将结果分割为两种结果集(如性别男女,成绩是否及格)
Map<Boolean, List<Student>> collect = students.stream().collect(partitioningBy(s -> computeGPA(s) > 162));
//groupingBy()  根据结果进行分组,如下: 根据学生的成绩GPA总和进行分组
Map<Integer, List<Student>> collect = students.stream().collect(groupingBy(s -> computeGPA(s)));

转map处有个要点:Function是一个接口,直接调用了其内部的一个静态实现类identity(),那是因为java8支持在接口添加具体的实现方法,这么做是因为若想继续在collection接口添加一个方法,实现该接口的所有方法都需要实现对应的方法,因此java8提供了方法的默认实现及其静态方法(default,static修饰的方法)

join:字符串拼接
Stream<String> stream = Stream.of("I", "love", "you");
//String joined = stream.collect(Collectors.joining());// "Iloveyou"
//String joined = stream.collect(Collectors.joining(","));// "I,love,you"
String joined = stream.collect(Collectors.joining(",", "{", "}"));// "{I,love,you}"

Stream 实现详解

中间操作:

​ 只做标记操作无直接实现。其中分为无状态中间操作(元素的处理不受前面元素影响,如map、flatMapToLong)有状态中间操作(必须等所有元素处理完毕才能得出结果,如max、distinct、sort)

结束操作:

​ 触发实际操作。其中分为短路操作(无需处理所有元素即可得出结果,如anyMatch、allMatch)非短路操作(需要遍历所有元素,如foreach、reduce)

Optional

empty():创建一个空的optional实例
Optional<User> emptyOpt = Optional.empty();
of():创建Optional实例,若参数为null将会抛出NPE
Optional<Person> person11 = Optional.of(person1);
ofNullable():创建Optional实例,若参数为null不会抛出NPE
Optional<Person> person = Optional.ofNullable(person1);
orElse():若前者为null则返回orElse内容
Person person3 = Optional.ofNullable(person1).orElse(person2);
orElseGet():若前者为null则返回orElseGet内容
Person person3 = Optional.ofNullable(person1).orElseGet(person2);
orElse()、orElseGet()区别:
public void optionalTest(){
    Person person1 = null;
    Person person2 = new Person("KKGS",18);
    System.out.println("execute orEles...................");
    Person person3 = Optional.ofNullable(person2).orElse(newPerson());
    System.out.println("execute orElesGet...................");
    Person person5 = Optional.ofNullable(person2).orElseGet(()->newPerson());

}
static Person newPerson(){
    System.out.println("newPerson+++++++++++");
    return new Person();
}
//输出结果
execute orEles...................
newPerson+++++++++++
execute orElesGet...................

//可见当ofNullable内容不为空的情况下,orEles依然会执行newPerson() , 而orElesGet不会执行
orElseThrow():若对象为空的话则抛出异常
Person person = Optional.ofNullable(person2).orElseThrow(() -> new NullPointerException());
isPresent():判断值是否为null,返回Boolean值
ifPresent():若值不为空则执行consummer操作
Optional.ofNullable("null").ifPresent((a)-> System.out.println(a));

其中map、filter、操作与流式操作无异

并行流效率比较

//for循环
public static long iterativeSum(long n) {
    long result = 0;
    for (long i = 0; i <= n; i++) {
        result += i;
    }
    return result;
}
//普通流
public static long sequentialSum(long n) {
    return Stream.iterate(1L, i -> i + 1).limit(n).reduce(Long::sum).get();
}
//并行流
public static long parallelSum(long n) {
    return Stream.iterate(1L, i -> i + 1).limit(n).parallel().reduce(Long::sum).get();
}
//包装类型流
public static long rangedSum(long n) {
    return LongStream.rangeClosed(1, n).reduce(Long::sum).getAsLong();
}
//包装类型并行流
public static long parallelRangedSum(long n) {
    return LongStream.rangeClosed(1, n).parallel().reduce(Long::sum).getAsLong();
}

************************************************************************************
method1: 2 msecs
method2: 77 msecs
method3: 101 msecs
method4: 8 msecs
method5: 2 msecs
************************************************************************************

有的人会轻易得到一个结论:并行流很快,我们可以完全放弃 foreach/fori/iter 外部迭代,使用 Stream 提供的内部迭代来实现了。

事实真的是这样吗?并行流真的如此完美吗?答案当然是否定的。大家可以复制下面的代码,在自己的电脑上测试。测试完后可以发现,并行流并不总是最快的处理方式。

  1. 对于 iterate 方法来处理的前 n 个数字来说,不管并行与否,它总是慢于循环方式,非并行版本可以理解为流化操作没有循环更偏向底层导致的慢。可并行版本是为什么慢呢?这里有两个需要注意的点:
  • iterate 生成的是装箱的对象,必须拆箱成数字才能求和
  • 我们很难把 iterate 分成多个独立的块来并行执行

这个问题很有意思,我们必须意识到某些流操作比其他操作更容易并行化。对于 iterate 来说,每次应用这个函数都要依赖于前一次应用的结果。因此在这种情况下,我们不仅不能有效的将流划分成小块处理。反而还因为并行化再次增加了开支。

  1. 而对于 LongStream.rangeClosed() 方法来说,就不存在 iterate 的第两个痛点了。它生成的是基本类型的值,不用拆装箱操作,另外它可以直接将要生成的数字 1 ~n 拆分成 1 ~ n/4, 1n/4 ~ 2n/4, 3n/4 ~ n 这样四部分。因此并行状态下的 rangeClosed() 是快于 for 循环外部迭代的:
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值