java8 lambda 相关操作

详情看:
英文:https://github.com/shekhargulati/java8-the-missing-tutorial
比较好的博文:
https://www.cnblogs.com/aspirant/p/10132730.html.
https://blog.csdn.net/u013291394/article/details/52662761.

交集与并集

/*并集*/
    List<AClass> unionResult = Stream.of(aClassList1, aClassList2)
    	.flatMap(Collection::stream)
    	.distinct()
    	.collect(Collectors.toList());
    assertEquals(unionResult.size(), 5);
    System.out.println(unionResult);
 	/*交集*/
    /*[AClass(id=1, name=zhuoli1, description=haha1)]*/
    List<AClass> intersectResult = aClassList1.stream()
    	.filter(aClassList2::contains)
    	.collect(Collectors.toList());
    System.out.println(intersectResult);
	//交集
    Collection<String> intersection = CollectionUtils.intersection(listA, listB);

flatMap

  • flatMap ——合并多个list
/*合并多个list*/
    List<AClass> aClassListResult = map.values().stream()
    	.flatMap(listContainer -> listContainer.getLst().stream())
    	.collect(Collectors.toList());
    /*注意跟并集的区别*/
    assertEquals(aClassListResult.size(), 6);
  • flatMap ——对给定单词列表 [“Hello”,“World”],你想返回列表[“H”,“e”,“l”,“o”,“W”,“r”,“d”]
	String[] words = new String[]{"Hello","World"};
	List<String> a = Arrays.stream(words)
                .map(word -> word.split(""))
                .flatMap(Arrays::stream)
                .distinct()
                .collect(toList());
	a.forEach(System.out::print);
  • flatMap的复杂操作,List<Data1>和List<Data2>根据Id进行连接,将连接结果输出为一个List<OutputData>:

@Data
@AllArgsConstructor
public class Data1 {
    private int id;
    private String name;
    private int amount;
}
 
@Data
@AllArgsConstructor
public class Data2 {
    private int id;
    private String name;
    private String type;
}
 
@Data
@AllArgsConstructor
public class OutputData {
    private int id;
    private String name;
    private String type;
    private int amount;
}
 
 
@Test
public void intersectByKeyTest(){
    List<Data2> listOfData2 = new ArrayList<Data2>();
    listOfData2.add(new Data2(10501, "JOE"  , "Type1"));
    
    List<Data1> listOfData1 = new ArrayList<Data1>();
    listOfData1.add(new Data1(10501, "JOE"    ,3000000));

    List<OutputData> result = listOfData1.stream()
            .flatMap(x -> listOfData2.stream()
                    		.filter(y -> x.getId() == y.getId())
                    		.map(y -> new OutputData(y.getId(), x.getName(), y.getType(), x.getAmount())))
            .collect(Collectors.toList());
    System.out.println(result);
 
    /*difference by key*/
    List<Data1> data1IntersectResult = listOfData1.stream()
    	.filter(data1 -> listOfData2.stream()
 					.map(Data2::getId)
 					.collect(Collectors.toList())
 					.contains(data1.getId()))
 		.collect(Collectors.toList());
    System.out.println(data1IntersectResult);

  • 使用flatMap统计——字数统计样例
public static void wordCount(Path path) throws IOException {
    Map<String, Long> wordCount = Files.lines(path)
            .parallel()
            .flatMap(line -> Arrays.stream(line.trim().split("\\s")))
            .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase().trim())
            .filter(word -> word.length() > 0)
            .map(word -> new SimpleEntry<>(word, 1))
            .collect(groupingBy(SimpleEntry::getKey, counting()));
    wordCount.forEach((k, v) -> System.out.println(String.format("%s ==>> %d", k, v)));
}
  • faltMapToInt、flatMapToDouble、flatMapToLong
List<List<String>> listOfLists = Arrays.asList(
            Arrays.asList("1", "2"),
            Arrays.asList("5", "6"),
            Arrays.asList("3", "4")
    );
 
    IntStream intStream =
            listOfLists.stream()
                    .flatMapToInt(childList ->
                            childList.stream()
                                    .mapToInt(Integer::new));
 
    int sum = intStream.peek(System.out::println).sum();
    System.out.println("sum: " + sum);

Collectors

下表展示 Collectors 类的静态工厂方法。

工厂方法 返回类型 作用

  • toList List 把流中所有项目收集到一个 List
  • toSet Set 把流中所有项目收集到一个 Set,删除重复项
  • toCollection Collection 把流中所有项目收集到给定的供应源创建的集合
  • menuStream.collect(toCollection(), ArrayList::new)
  • counting Long 计算流中元素的个数
  • sumInt Integer 对流中项目的一个整数属性求和
  • averagingInt Double 计算流中项目 Integer 属性的平均值
  • summarizingInt IntSummaryStatistics 收集关于流中项目 Integer 属性的统计值,例如最大、最小、 总和与平均值
  • joining String 连接对流中每个项目调用 toString 方法所生成的字符串collect(joining(", "))
  • maxBy Optional 一个包裹了流中按照给定比较器选出的最大元素的 Optional, 或如果流为空则为 Optional.empty()
  • minBy Optional 一个包裹了流中按照给定比较器选出的最小元素的 Optional, 或如果流为空则为 Optional.empty()
  • reducing 归约操作产生的类型 从一个作为累加器的初始值开始,利用 BinaryOperator 与流 中的元素逐个结合,从而将流归约为单个值累加int totalCalories = menuStream.collect(reducing(0, Dish::getCalories, Integer::sum));
  • collectingAndThen 转换函数返回的类型 包裹另一个收集器,对其结果应用转换函数int howManyDishes = menuStream.collect(collectingAndThen(toList(), List::size))
  • groupingBy Map<K, List> 根据项目的一个属性的值对流中的项目作问组,并将属性值作 为结果 Map 的键
  • partitioningBy Map<Boolean,List> 根据对流中每个项目应用谓词的结果来对项目进行分区

工作中遇到的tomap方式
// if (!CollectionUtils.isEmpty(dpsCharVars)) {
// 用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
// Map<String, CharVar> charVarMap = dpsCharVars.parallelStream()
// .collect(Collectors.toMap(CharVar::getEnName, var -> var, (k1, k2) -> k1));
// }

  • Collectors toMap,当value为null时空指针报错 的处理方式如下:
params.stream().collect(LinkedHashMap::new, (m, v) -> m.put(v.getParam(), v.getParamValue()), LinkedHashMap::putAll);

罪魁祸首就是HashMap的merge方法了,它的第一行就是这个:

if (value == null)
           throw new NullPointerException();

为什么会调merge方法呢,toMap方法调的

public static <T, K, U, M extends Map<K, U>>
   Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                              Function<? super T, ? extends U> valueMapper,
                               BinaryOperator<U> mergeFunction,
                              Supplier<M> mapSupplier) {
       BiConsumer<M, T> accumulator
               = (map, element) -> map.merge(keyMapper.apply(element),
                                             valueMapper.apply(element), mergeFunction);
       return new CollectorImpl<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
   }

那么怎么解决呢? 既然时merge方法造成的,那就不调merge方法。 我们用自己定义的accumulator,用Stream的另一个collect方法

<R> R collect(Supplier<R> supplier,
                BiConsumer<R, ? super T> accumulator,
                BiConsumer<R, R> combiner);

这个方法上面的注释写了一段这个, 前两个参数干什么用的就很清楚了,第三个参数时并行计算用来组合结果的,所以用HashMap的putAll就好了

R result = supplier.get();
for (T element : this stream)
    accumulator.accept(result, element);
return result;

所以解决办法的代码大概就是这样的

params.stream().collect(LinkedHashMap::new, (m, v) -> m.put(v.getParam(), v.getParamValue()), LinkedHashMap::putAll);

据说这个问题java9就修复了,所以也可以尝试升级jdk


Consumer

public class MyTest {
    public static void  printValur(String str){
        System.out.println("print value : "+str);
    }
 
    public static void main(String[] args) {
        List<String> al = Arrays.asList("a", "b", "c", "d");
        al.forEach(AcceptMethod::printValur);
        //下面的方法和上面等价的
        Consumer<String> methodParam = AcceptMethod::printValur; //方法参数
        al.forEach(x -> methodParam.accept(x));//方法执行accept
    }
}
上面的所有方法执行玩的结果都是如下:
print value : a
print value : b
print value : c
print value : d

在JDK8中,接口Iterable 8中默认实现了forEach方法,调用了 JDK8中增加的接口Consumer内的accept方法,执行传入的方法参数。

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

另外补充一下,JDK8改动的,在接口里面可以有默认实现,就是在接口前加上default,实现这个接口的函数对于默认实现的方法可以不用再实现了。类似的还有static方法。现在这种接口除了上面提到的,还有BiConsumer,BiFunction,BinaryOperation等,在java.util.function包下的接口,大多数都有,后缀为Supplier的接口没有和别的少数接口。


最近新看到的lambda表达式,对我的collect操作起到了很大的促进作用:
需求起源于:如何将一个List<A> 转换成Map<String,List<B>> ???

        characterRangeList.stream().collect(Collectors.groupingBy(new Function<A, Integer>() {
                    @Override
                    public Integer apply(A aa) {
                        return aa.getVarId();
                    }
                }, HashMap::new, Collectors.mapping(new Function<A, B>() {
                    @Override
                    public B apply(A aa) {
                        return null;
                    }
                }, Collectors.toList())))
                .entrySet().stream().map(new Function<Map.Entry<String, List<Integer>>, B>() {
                    @Override
                    public B apply(Map.Entry<String, List<Integer>> stringListEntry) {
                        return new B(stringListEntry.getKey(), stringListEntry.getValue());
                    }
                }).collect(Collectors.toList());

        System.out.println(JSON.toJSONString(listB));

Function

    public static void main(String[] args) {
        Function<Integer, Integer> times2 = i -> i*2;
        Function<Integer, Integer> squared = i -> i*i;
        
        System.out.println(times2.apply(4));
        
        System.out.println(squared.apply(4));
        
		//32                先4×4然后16×2,先执行apply(4),在times2的apply(16),先执行参数,再执行调用者。
        System.out.println(times2.compose(squared).apply(4));  
        
        //64               先4×2,然后8×8,先执行times2的函数,在执行squared的函数。
        System.out.println(times2.andThen(squared).apply(4));  
        
		 //16
        System.out.println(Function.identity().compose(squared).apply(4));  
    }

computeIfAbsent

在使用 Map 时推荐一个不错的函数 computeIfAbsent:

  • 只有在当前 Map 中 key 对应的值不存在或为 null 时, 才调用 mappingFunction
  • 并在 mappingFunction 执行结果非 null 时, 将结果跟 key 关联.
	/**
	 * mappingFunction 为空时 将抛出空指针异常
	 */
	public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

	Map<String, List<String>> map = new HashMap<>();
	List<String> list;
	
	// 一般这样写
	list = map.get("list-1");
	if (list == null) {
	    list = new LinkedList<>();
	    map.put("list-1", list);
	}
	list.add("one");
	
	// 使用 computeIfAbsent 可以这样写
	list = map.computeIfAbsent("list-1", k -> new ArrayList<>());
	list.add("one");

orElse() 和 orElseGet()的区别

Optional.ofNullable(record)
                    .map(columns -> ...)
                    .orElse(Maps.newHashMap());
                    
Optional.ofNullable(record)
                    .map(columns -> ...)
                    .orElseGet(()->Maps.newHashMap());
累积 —— reduce
        Arrays.asList(1, 2, 3, 4).stream().reduce((a, b) -> a * b).get();//24

遍历移除

  List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add(4);
    list.removeIf(s -> s%2==0);               // 过滤掉模2等于0的数
    list.forEach(s -> System.out.println(s)); // 输出 1 3

    List<String> strings = new ArrayList<>();
    strings.add("ab");
    strings.add("ac");
    strings.add("bc");
    strings.add("cd");
    Predicate<String> predicate = (s) -> s.startsWith("a"); // 这里单独定义了过滤器
    strings.removeIf(predicate);                            // 过滤掉以"a"开头的元素
    strings.forEach(s -> System.out.println(s));            // 输出 bc cd
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值