lambda表达式总结

Lambda
Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作中,可以极大地优化代码结构
为什么用lambda
 1、使用Lambda表达式可以使代码变的更加紧凑,例如在Java中实现一个线程,只输出一个字符串Hello World!,我们的代码如下所示: 
public static void main(String[] args) throws Exception {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("Hello World!");
        }
    }).start();
}

使用Lambda表达式之后代码变成如下形式:

public static void main(String[] args) throws Exception {
    new Thread(() -> System.out.println("Hello World!")).start();
}

Streams

      就是JAVA8提供给我们的对于元素集合统一、快速、并行操作的一种方式。它能充分运用多核的优势,以及配合lambda表达式、链式结构对集合等进行许多有用的操作

作用: 
提供了一种操作 大数据接口,让数据操作更容易和更快 
使用stream,我们能够对collection的元素进行过滤、映射、排序、去重等许多操作。

中间方法和终点方法: 
它具有过滤、映射以及减少遍历数等方法,这些方法分两种:中间方法和终端方法, 
“流”抽象天生就该是持续的,中间方法永远返回的是Stream,因此如果我们要获取最终结果的话, 
必须使用终点操作才能收集流产生的最终结果。区分这两个方法是看他的返回值, 
如果是Stream则是中间方法,否则是终点方法
1、 过滤 filter(): 
 
月薪超过10000美元员工
List<Person> personList = new ArrayList<Person>()

personList .stream()
        .filter((p) -> (p.getSalary() > 10000))
        .forEach((p) -> System.out.println(p.getName());
//统计数量
Long rel = personList.stream()
         .filter(p -> p.getAge() > 18)
         .count();

自定义过滤器

Predicate<Person> ageFilter = (p) -> (p.getAge() > 25);
Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 10000);

年龄大于25岁,月薪10K以上
personList .stream()
        .filter(ageFilter)
        .filter(genderFilter)
        .forEach((p) -> System.out.println(p.getName()));

2、limit限制获取个数

获取3个大于25岁的人
personList .stream()
        .filter(genderFilter)
        .limit(3)
        .forEach((p) -> System.out.println(p.getName()));
3、排序
 
List排序
根据薪资升序排列
personList.stream()
        .sorted( (p, p2) -> (p.getSalary() - p2.getSalary()) )
        .collect( Collectors.toList() );

根据年龄升序排列
personList.stream()
       .sorted(Comparator.comparing(Person::getAge))
        .collect(Collectors.toList());
降序排序
personList.stream()
      .sorted(Comparator.comparing(Person::getAge).reversed())
      .collect(Collectors.toList());

//map排序
 Map<String, Integer> map = new HashMap();
 map.put("349", 12);
 map.put("329", 13);
 map.put("6", 14);
 map.put("399", 15);
 map.put("99", 16);

 map = map.entrySet()
       stream()
       .sorted(Map.Entry.<String, Integer>comparingByKey()) 
      .collect(Collectors.toMap(k -> k.getKey(), v -> v.getValue(),
                        (k, v) -> k, LinkedHashMap::new));

comparingByKey()根据键排序,comparingByValue 根据值排序


对最低和最高的薪水感兴趣,比排序后选择第一个/最后一个 更快的是min和max方法

Person pers = personList
        .stream()
        .min((p1, p2) -> (p1.getSalary() - p2.getSalary()))
        .get()

Person pers = personList
        .stream()
        .max((p1, p2) -> (p1.getSalary() - p2.getSalary()))
        .get()

4、计算合

(1)
personList
      .stream()
      .map(Person::getSalary)
      .reduce(BigDecimal.ZERO, BigDecimal::add);
(2)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream().reduce((x, y) -> x + y).get();

(3)
 personList
      .parallelStream()  
      .mapToInt(p -> p.getSalary())          //mapToDouble()、mapToLong()
      .sum();  
问题:并行流
(4)
//reduce使用 acc中间结果(会使用第一个元素的地址)、bb是Stream的元素
会修改person对象中的值 不推荐
personList.stream()
        .reduce((acc, bb) -> {
            acc.setAge(acc.getAge() + bb.getAge());
            acc.setSalary(acc.getSalary() + bb.getSalary());
            return acc;
        }).get();

(5)
//方式二  初始化一个对象,中间结果使用此地址
Person person0 = new Person();
Person person= personList
            .stream()
            .reduce(person0, (person1, person2) -> {
                    person1.setSalary(person1.getSalary() + person2.getSalary());
                    person1.setAge(person1.getAge() + person2.getAge());
                    return person1;
                });
(6)
//将集合分类放入map中并求和
 Map<String, Integer> studentScoreMap = new HashMap<>();
  List<StudentScore> studentScoreList = buildATestList();
//转换
        studentScoreList.forEach(studentScore -> studentScoreMap.merge(
          studentScore.getStuName(),
          studentScore.getScore(),
          Integer::sum));

5、去重:distinct()


List<int> numbers = Arrays.asList(1, 2, 3, 4, 5, 5, 5, 5, 6, 7);

List<int> distinctNumbers = numbers.stream()
                .distinct()
                .collect(Collectors.toList());

distinct()方法并不能设置条件. 解决方案如下:
首先定义一个过滤器:

public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
    Map<Object, Boolean> seen = new ConcurrentHashMap<>();
    return object -> seen.putIfAbsent(keyExtractor.apply(object), Boolean.TRUE) == null;
}
再去重
List<Person> distinctUsers =personList.stream()
        .distinct(distinctByKey(Person::getName))
        .collect(Collectors.toList());


personList
                .stream().collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getName))), ArrayList::new));

多字段去重

   personList= personList.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(
                        o -> o.getName() + ";" + o.getAge()))), ArrayList::new));
6、collect()
(1)list转map
这个方式出现键值重复时会报错
Map<Integer, String> map =personList.stream().collect(Collectors.toMap(Person::getAge,Person::getName))


key重复时报错的解决,将第二次出现的值覆盖第一个
Map<Integer, String> map2 =personList
        .stream()
        .collect(Collectors.toMap(Person::getAge,Person::getName,(k2,k1)->k1));

出现重复时将俩者拼接返回
Map<Integer, String> map2 =personList
        .stream()
        .collect(Collectors.toMap(Person::getAge,Person::getName,(k2,k1)->k1+","+k2));

出现重复时加入一个集合中
Map<Integer, List<String>> map = personList.stream().collect(Collectors.toMap(Person :: getAge,
        // 此时的value 为集合,方便重复时操作
        s ->  {
            List<String> studentNameList = new ArrayList<>();
            studentNameList.add(s.getName());
            return studentNameList;
        },
        // 重复时将现在的值全部加入到之前的值内
        (List<String> value1, List<String> value2) -> {
            value1.addAll(value2);
            return value1;
        }
));

结果示例:
{20岁:[张三, 李四], 25岁:[王二, 麻子]}

抽取指定key,value为对象
Map<Integer, Person> map =personList.stream().collect(Collectors.toMap(Person::getId,person->person))

(2)分组

根据id分组
Map<Long, List<Person>> groupByMap = personList.stream().collect(Collectors.groupingBy(Person::getId));

分组并统计
Map<Integer, Long> collect =persionList.stream().collect(Collectors.groupingBy(Person::getAge, counting()))

   Map<Integer, Long> curriculum = articleList.stream()
                .collect(Collectors.groupingBy(Article::getZhuanlanId, Collectors.summingLong(article->articleMap.getOrDefault(article.getId(), 0L))));

分组并取指定属性
Map<Integer, List<String>> part = personList
        .stream()
        .collect(Collectors.groupingBy(Person::getAge,Collectors.mapping(Person::getName, toList())));

分区是分组的特殊情况。  它最多可以分为两组,如id大于2和不大于2的
 Map<Boolean, List<Person>> part = personList
        .stream()
        .collect(Collectors.partitioningBy(x->x.getAge()>2));

分组并排序
Map<String, List<Person>> collectMap = personList.stream()
                    .sorted(Comparator.comparing(Person::getSex))
                    .collect(Collectors.groupingBy(Person::getAge,TreeMap::new,Collectors.toList()));

groupingBy和partitioningBy的区别

我们先来看官方源码说明
public static <T, K> Collector<T, ?, Map<K, List<T>>>
    groupingBy(Function<? super T, ? extends K> classifier) {
        return groupingBy(classifier, toList());
    }
groupingBy的函数参数为Function然后他的返回值也是Map,但是他的key是泛型,那么这个分组就会将数据分组成多个key的形式。
我们再来看下partitioningBy
Collector<T, ?, Map<Boolean, List<T>>> partitioningBy(Predicate<? super T> predicate) {
    return partitioningBy(predicate, toList());
}
可以看出函数的参数一个Predicate接口,那么这个接口的返回值是boolean类型的,也只能是boolean类型,然后他的返回值是Map的key是boolean类型,也就是这个函数的返回值只能将数据分为两组也就是ture和false两组数据。
(3)joining
name用逗号相连
    String join = personList.stream().map(Person::getName).collect(Collectors.joining(","));
性能问题
     有些细心的同学可能会有这样的疑问:在对于一个Stream进行多次转换操作,每次都对Stream的每个元素进行转换,而且是执行多次,这样时间复杂度就是一个for循环里把所有操作都做掉的N(转换的次数)倍啊。其实不是这样的,转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在汇聚操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值