Java8中Lambda和Stream,优雅的处理集合

Lambda表达式

new Thread(()->{
			System.out.println("girl");
		}).start();

以上就是一个简单的例子,新增一个线程来输出“girl”
其实可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它 有参数列表、函数主体、返回类型

函数式接口

一言以蔽之,函数式接口就是只定义一个抽象方法的接口
函数式接口是我们能使用lambda表达式的一个基本条件,如上面我们输出 “girl” 在Java8以前我们最方便的写法是使用匿名内部类

new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("girl");
			}
		}).start();

那为什么Runnable接口的事例为什么能直接用lambda的方式作为参数直接传给Thread呢,以下是Runnable的源码
可以看到 @FunctionalInterface 注解已经标明了这个接口是一个函数式接口
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作 函数描述符。例如,Runnable接口可以看作一个什么也不接受什么也不返回(void)的函数的 签名,因为它只有一个叫作run的抽象方法,这个方法什么也不接受,什么也不返回(void)。① 我们在本章中使用了一个特殊表示法来描述Lambda和函数式接口的签名。() -> void代表 了参数列表为空,且返回void的函数。这正是Runnable接口所代表的。

@FunctionalInterface
public interface Runnable {
  
    public abstract void run();
}

使用函数式接口

函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作 函数描述符。例如,Runnable接口可以看作一个什么也不接受什么也不返回(void)的函数的 签名,因为它只有一个叫作run的抽象方法,这个方法什么也不接受,什么也不返回(void),我们使用了一个特殊表示法来描述Lambda和函数式接口的签名。() -> void代表 了参数列表为空,且返回void的函数。这正是Runnable接口所代表的,下面几个其他的例子

1.用 Comparator 对List进行排序

List<Integer> list = Arrays.asList(4, 2, 5, 3, 1);
		list.sort((o1,o2)->{
			return o1.compareTo(o2);
		});
		System.out.println(list);

运行打印 [1, 2, 3, 4, 5]

2.用 Predicate 过滤List中需要的元素

   //过滤List的公用方法
   public static <T> List<T> filter(List<T> list, Predicate<T> p) {
   	List<T> results = new ArrayList<>();
   	for (T s : list) {
   		if (p.test(s)) {
   			results.add(s);
   		}
   	}
   	return results;
   }
   
   public static void main(String[] args) {
   	List<Integer> list = Arrays.asList(4, 2, 5, 3, 1, 11, 12);
   	System.out.println(filter(list, (Integer i) -> i > 10));
   }

运行打印[11, 12] 如代码中我 i>10 作为过滤条件传入filter方法过滤大于10的元素,也可以传 < 10 的条件或者其他条件 筛选需要的数据 这里的条件其实就是 Predicate类中test函数式接口的实现,即我们把一个函数作为参数传给另一个函数来应对不同的 需求,这就是函数式编程。

3.用 Consumer消费list元素

   public static void main(String[] args) {
       User [] users = new User[]{
               new User(1001,"黄蓉",(byte)0,30),
               new User(1002,"郭靖",(byte)1,35),
               new User(1003,"小龙女",(byte)0,20),
               new User(1004,"杨过",(byte)1,20),};

       List<User> userList =  Arrays.asList(users);
       consumer(userList,user -> System.out.println(user.getUserName()));
   }
   public static  <T> void consumer(List<T> list, Consumer<T> c){
       for (T t :list){
           c.accept(t);
       }
   }

打印输出所有的用户名
黄蓉
郭靖
小龙女
杨过
4.用Function 转换对象

public static void main(String[] args) {
       User [] users = new User[]{
               new User(1001,"黄蓉",(byte)0,30),
               new User(1002,"郭靖",(byte)1,35),
               new User(1003,"小龙女",(byte)0,20),
               new User(1004,"杨过",(byte)1,20),};

       List<User> userList =  Arrays.asList(users);
       List<String> userNames = mapping(userList, user -> user.getUserName());
       System.out.println(userNames);
   }

   public  static <T, R> List<R> mapping(List<T> list, Function<T, R> f) {
       List<R> result = new ArrayList<>();
       for(T s: list){
           result.add(f.apply(s));
       }
       return result;
   }

打印输出 [黄蓉, 郭靖, 小龙女, 杨过],我们只需传入不同的表达式既可转换成不同的对象

用Stream优雅的处理集合

以下所有例子都用这个User对象作为操作对象

   public class User {
       private Integer userId;
       private Integer userName;
       private Byte userSex;// 0=女,1=男
       private Integer userAge;
   }
public static void main(String[] args) {        
       User [] users = new User[]{
               new User(1001,"黄蓉",(byte)0,30),
               new User(1002,"郭靖",(byte)1,35),
               new User(1003,"小龙女",(byte)0,20),
               new User(1004,"杨过",(byte)1,20),};

       List<User> userList =  Arrays.asList(users);
   }

获取用户列表中的 userId列表

List<Integer> userIds = userList.stream().map(User::getUserId).collect(Collectors.toList());
System.out.println(userIds);

运行打印[1001, 1002, 1003, 1004]

把list转成map

Map<Integer, String> userNameMap = userList.stream().collect(Collectors.toMap(User::getUserId, User::getUserName));
System.out.println(userNameMap);

运行打印{1001=黄蓉, 1002=郭靖, 1003=小龙女, 1004=杨过}

list转成map,并防止key或value为null时报(NullPointerException)

HashMap<Object, Object> userNameMap = userList.stream().collect(HashMap::new, (m, p) -> m.put(p.getUserId(), p.getUserName()), HashMap::putAll);
System.out.println(userNameMap);

运行打印{1001=黄蓉, 1002=郭靖, 1003=小龙女, 1004=杨过}

list转成map,并处理重复数据

Map<Integer, String> userNameMap = userList.stream().collect(Collectors.toMap(User::getUserId, User::getUserName, (u1, u2) -> u1));
System.out.println(userNameMap);

运行打印{1001=黄蓉, 1002=郭靖, 1003=小龙女, 1004=杨过}

分组保持原来顺序

returnRemindList.stream().collect(Collectors.groupingBy(TopicRemindSettingBO::getRemindPhone, LinkedHashMap::new, Collectors.toCollection(ArrayList::new)));

list分组

Map<Byte, List<User>> groupUserMap = userList.stream().collect(Collectors.groupingBy(User::getUserSex));
System.out.println(groupUserMap);

list分组只保留一个value

      Map<String, Rule> ruleMap = ruleList.stream().
              .collect(Collectors.groupingBy(Rule::getId,
                      Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))));

list分组并对value进行排序

      Map<Integer, User> promotionTypeMap = activities.stream().collect(Collectors.groupingBy(User::getAge
              , Collectors.collectingAndThen(Collectors.reducing((o1, o2) ->
                      Long.valueOf(o1.getId()).compareTo(Long.valueOf(o2.getId())) > 0 ? o1 : o2), Optional::get)));

这样就根据性别把userList分成了两个列表

分组升级(例如只需要对象中的某一个字段)

Map<String, List<Integer>> listMap = conditionVOList.stream().collect(
              Collectors.groupingBy(SurveyClassConditionVO::getClassType,
              Collectors.mapping(SurveyClassConditionVO::getId, Collectors.toList())));

获取list中所有userId拼接的以逗号分隔的字符串

String userIds = userList.stream().collect(Collectors.mapping(user -> String.valueOf(user.getUserId()), Collectors.joining(",")));
System.out.println(userIds);

运行打印 1001,1002,1003,1004

根据条件过滤列表中的元素

List<User> filterUsers = userList.stream().filter(user -> user.getUserAge() > 20).collect(Collectors.toList());
System.out.println(filterUsers);

这样就过滤掉了列表中age小于20的user

列表求和或者求平均值

int ageSum = userList.stream().mapToInt(User::getUserAge).sum();
OptionalDouble average = userList.stream().mapToInt(User::getUserAge).average();

System.out.println("ageSum : " + ageSum);
System.out.println("average : " + average.getAsDouble());

这样既可计算出年龄的总和和平均值,运行打印
ageSum : 105
average : 26.25

快速遍历map集合

Map<Integer, String> userMap = userList.stream().collect(Collectors.toMap(User::getUserId, user -> user.getUserName()));
userMap.forEach((userId, userName) -> {
      System.out.println(userId + ":" + userName);
});

直接forEach然后把key和value通过lambda表达式传入既可

排序

userList.sort(Comparator.comparing(User::getAge,Comparator.nullsLast(Comparator.reverseOrder())));

List去重

userList = userList.stream().distinct().collect(Collectors.toList());

List根据对象属性去重

userList = userList.stream().filter(distinctByKey(info->info.getUserName())).collect(Collectors.toList());

需要自定义一个方法

private  <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
       Map<Object,Boolean> seen = new ConcurrentHashMap<>();
       return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
   }

List根据对象多个属性去重

  questionSnapshotInfoList = questionSnapshotInfoList.stream().collect(
               Collectors.collectingAndThen(
                       Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o->o.getId()+o.getRangeEnd()))), ArrayList::new)
       );

数组快速转List

String[] arrays = {"tom", "jack", "kate"};
List<String> stringList= Stream.of(arrays).collect(Collectors.toList());
List<Integer> intList= Arrays.stream(new int[] { 1, 2, 3, }).boxed().collect(Collectors.toList());
List<Long> longList= Arrays.stream(new long[] { 1, 2, 3 }).boxed().collect(Collectors.toList());
List<Double> doubleList= Arrays.stream(new double[] { 1, 2, 3 }).boxed().collect(Collectors.toList());

最后记录一篇不错的文章
https://www.jianshu.com/p/11c925cdba50

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值