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