java8 Lambda Stream 常用详细实例

在集合转换和遍历的时候,你还在使用for循环吗?
for循环缺点:
1.复杂转换 转换时赋值极易出现错误和bug
2.遍历时,要写很多冗余代码。

综上所述:
1.是时候使用java8 Lambda表达式,Stream,Collect, Collectors了
2.流式编程,函数编程是java未来的趋势,最新的Spring5 WebFlux 异步(响应式)流编程

java8 Lambda Stream collect Collectors 常用详细实例
https://blog.csdn.net/fzy629442466/article/details/84629422
java集合遍历
https://blog.csdn.net/fzy629442466/article/details/84622757

Stream的使用分为两种类型:
Intermediate,一个Stream可以调用0到多个Intermediate类型操作,每次调用会对Stream做一定的处理,返回一个新的Stream,这类操作都是惰性化的(lazy),就是说,并没有真正开始流的遍历。
常用操作:map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel

Terminal,一个Stream只能执行一次terminal 操作,而且只能是最后一个操作,执行terminal操作之后,Stream就被消费掉了,并且产生一个结果。
常用操作:forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny

实例:
任何集合都可以转换为Stream:
数组 转Stream

String[] strArr = new String[]{"aa","bb","cc"};
Stream<String> streamArr = Stream.of(strArr);
Stream<String> streamArr2 = Arrays.stream(strArr);

List集合 转Stream

List<String> list = new ArrayList<>();
Stream<String> streamList = list.stream();

Map集合 转Stream

Stream stream = map.entrySet().stream();

List集合 转并行Stream

Stream<String> streamList2 = list.parallelStream();

/********** Intermediate **********/
filter 过滤操作

streamArr.filter(str -> str.startsWith("a"));

list.stream().filter(student -> student.getSex().equals("G")).forEach(student -> System.out.println(student.toString()));

List nums = Arrays.asList(1, 3, null, 8, 7, 8, 13, 10);
nums.stream().filter(num -> num != null).distinct().forEach(System.out::println);

Stream.of(1, 2, 3, 4, 5).filter(item -> item > 3).forEach(System.out::println);
// 打印结果:4,5

list.stream().filter(TestObject::isLeader).collect(Collectors.toList());

//Java 8 Map Filter 过滤示例
//Java 8之前:
String result = "";
for (Map.Entry<Integer, String> entry : maps.entrySet()) {
	if("something".equals(entry.getValue())){
		result = entry.getValue();
	}
}
//在Java 8中,您可以转换Map.entrySet()到stream由遵循filter()和collect()它。
//Map -> Stream -> Filter -> String
String result = maps.entrySet().stream()
	.filter(map -> "something".equals(map.getValue()))
	.map(map->map.getValue())
	.collect(Collectors.joining());
//Map -> Stream -> Filter -> MAP
Map<Integer, String> collect = maps.entrySet().stream()
	.filter(map -> map.getKey() == 2)
	.collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));

map 遍历和转换操作
还有提供:mapToDouble,mapToInt,mapToLong

streamArr.map(String::toLowerCase);

list.stream().map(TestObject::getName).collect(Collectors.toList()).forEach(System.out::println);

list.stream().map(TestObject::getName).map(String::length).collect(Collectors.toList()).forEach(System.out::println);

Stream.of("a", "b", "hello").map(item-> item.toUpperCase()).forEach(System.out::println);
// 打印结果 A, B, HELLO

List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList()); 

flatMap 将流展开


List<String> list1 = new ArrayList<>();
list1.add("aa");
list1.add("bb");
List<String> list2 = new ArrayList<>();
list2.add("cc");
list2.add("dd");
Stream.of(list1,list2).flatMap(str -> str.stream()).collect(Collectors.toList()); 

Stream<List<Integer>> inputStream = Stream.of(
 Arrays.asList(1),
 Arrays.asList(2, 3),
 Arrays.asList(4, 5, 6)
 );
Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream());

//获取 foo
class Outer {
    Nested nested;
}
class Nested {
    Inner inner;
}
class Inner {
    String foo;
}
Optional.of(new Outer())
    .flatMap(o -> Optional.ofNullable(o.nested))
    .flatMap(n -> Optional.ofNullable(n.inner))
    .flatMap(i -> Optional.ofNullable(i.foo))
    .ifPresent(System.out::println);

limit 提取子流 最大长度限制

streamArr.limit(1);

Stream.of(1, 2, 3,4,5).limit(2).forEach(System.out::println);
// 打印结果 1,2

skip 跳过

streamArr.skip(1);

Stream.of(1, 2, 3,4,5).skip(2).forEach(System.out::println); 
// 打印结果 3,4,5

peek 产生相同的流,支持每个元素调用一个函数

streamArr.peek(str -> System.out.println("item:"+str));

Stream.of(1, 2, 3, 4, 5).peek(integer -> System.out.println("accept:" + integer)).forEach(System.out::println);
// 打印结果: accept:1
// 1
// accept:2
// 2
// accept:3
// 3
// accept:4
// 4
// accept:5
// 5

distinct 去重

Stream.of("aa","bb","aa").distinct();
Stream.of(1,2,3,1,2,3).distinct().forEach(System.out::println); 
// 打印结果:1,2,3

// 根据id去重
List<Person> unique = appleList.stream().collect(collectingAndThen(toCollection(() -> new TreeSet<>(comparingLong(Apple::getId))), ArrayList::new));

sorted(),sorted(Comparator) 排序:

List<Human> humans = Lists.newArrayList(new Human("Sarah", 10), new Human("Jack", 12));
Collections.sort(humans, Comparator.comparing(Human::getName));
Assert.assertThat(humans.get(0), equalTo(new Human("Jack", 12)));
humans.sort((h1, h2) -> h1.getName().compareTo(h2.getName()));

反转排序

Comparator<Human> comparator = (h1, h2) -> h1.getName().compareTo(h2.getName());
humans.sort(comparator.reversed());

多条件排序

humans.sort((lhs, rhs) -> {
    if (lhs.getName().equals(rhs.getName())) {
        return lhs.getAge() - rhs.getAge();
    } else {
        return lhs.getName().compareTo(rhs.getName());
    }
});
Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));

多条件组合排序

humans.sort(Comparator.comparing(Human::getName).thenComparing(Human::getAge));
Assert.assertThat(humans.get(0), equalTo(new Human("Sarah", 10)));

students.sort((Student s1, Student s2) -> {return Integer.compare(s1.getHeight(), s2.getHeight());});
students.sort((s1, s2) -> Integer.compare(s1.getHeight(), s2.getHeight()));
students.sort(Comparator.comparingDouble(Student::getScore));
Stream.of("aaa","bb","c").sorted(Comparator.comparing(String::length).reversed());

Stream.of(1, 2, 3, 4, 5).sorted().forEach(System.out::println);
// 打印结果 5, 4, 3, 2, 1

parallel 转为并行流,谨慎使用

streamArr.parallel();

/********** Terminal **********/
forEach

streamArr.forEach(System.out::println);

int ids[] = new int[]{1, 2, 3, 4};
Arrays.stream(ids).forEach(System.out::println);

forEachOrdered 如果希望顺序执行并行流,请使用该方法

streamArr.parallel().forEachOrdered(System.out::println);

Stream.of(5,2,1,4,3).forEachOrdered(integer -> { System.out.println("integer:"+integer);}); 
// 打印结果 integer:5
// integer:2
// integer:1
// integer:4
// integer:3

toArray 收集到数组中

streamArr.filter(str -> str.startsWith("a")).toArray(String[]::new);

min 取最小值

IntStream.of(1,2,3,4).min();
Stream.of(arr).min(String::compareTo);

Optional<Integer> min = Stream.of(1, 2, 3, 4, 5).min((o1, o2) -> o1 - o2);
System.out.println("min:" + min.get());
// 打印结果:min:5

reduce 聚合操作

streamArr.reduce((str1,str2) -> str1+str2);
int sum2 = numbers.stream().reduce(0, (a,b) -> a + b);
//reduce 求最大值
Optional<Integer> max = numbers.stream().reduce(Integer::max);
//reduce 求最小值
Optional<Integer> min = numbers.stream().reduce(Integer::min);

max 取最大值

IntStream.of(1,2,3,4).max();
Stream.of(arr).max(String::compareTo);

Optional<Integer> max = Stream.of(1, 2, 3, 4, 5).max((o1, o2) -> o2 - o1);
System.out.println("max:" + max.get());
// 打印结果:max:1

count 计算总量

streamArr.count();

long count = Stream.of(1, 2, 3, 4, 5).count();
System.out.println("count:" + count);
// 打印结果:count:5

anyMatch 匹配 判断流中是否含有匹配元素

boolean hasMatch = streamArr.anyMatch(str -> str.startsWith("a"));
boolean anyMatch = Stream.of(1, 2, 3, 4).anyMatch(integer -> integer > 3);
System.out.println("anyMatch: " + anyMatch); 
// 打印结果:anyMatch: true 

if(list.stream().anyMatch(u -> u.getName().equals("Ron"))){
    System.out.println("Ron已经到了");
}

allMatch 匹配 判断流中是否全部匹配

boolean hasMatch = streamArr.allMatch(str -> str.startsWith("a"));

boolean allMatch = Stream.of(1, 2, 3, 4).allMatch(integer -> integer > 0);
System.out.println("allMatch: " + allMatch); 
// 打印结果:allMatch: true 

noneMatch 判断流中是否全部不匹配

boolean hasMatch = streamArr.noneMatch(str -> str.startsWith("a"));

boolean noneMatch = Stream.of(1, 2, 3, 4, 5).noneMatch(integer -> integer > 10);
System.out.println("noneMatch:" + noneMatch); 
// 打印结果 noneMatch:true

boolean noneMatch_ = Stream.of(1, 2, 3, 4, 5).noneMatch(integer -> integer < 3);
System.out.println("noneMatch_:" + noneMatch_); 
// 打印结果 noneMatch_:false

findFirst 找到第一个就返回

streamArr.filter(str -> str.startsWith("a")).findFirst();

//需要找到第一个isLeader为ture的对象并打印其名字,就可以按照如下的代码操作。
list.stream().filter(u->u.isLeader()).findFirst().ifPresent(u->System.out.println(u.getName()));

findAny 找到任意一个就返回

streamArr.filter(str -> str.startsWith("a")).findAny();

list.stream().filter(u -> u.getName().equals("Ron")).findAny().ifPresent(u -> System.out.println(u.getName()));

Concat 联接两个Stream:

Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5)).forEach(integer -> System.out.print(integer + ""));
// 打印结果: 1 2 3 4 5  

Stream流复用

Supplier<Stream<String>> streamSupplier = () -> Stream.of("d2", "a2", "b1", "b3", "c").filter(s -> s.startsWith("a"));

streamSupplier.get().anyMatch(s -> true);   // ok
streamSupplier.get().noneMatch(s -> true);  // ok

文件 Stream
把单词挑出来

List<String> output =reader.lines().
 flatMap(line ->Stream.of(line.split(REGEXP))).
 filter(word -> word.length() > 0).
 collect(Collectors.toList());

异步编排CompletableFuture和Stream结合用法:
单条流水线

public List<String> findPricesFutureOnePipeline(String product) {
    List<String> result = shops.stream()
        .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is "
            + shop.getPrice(product), executor))
        .map(CompletableFuture::join)
        .collect(Collectors.toList());
    return result;
  }
  
// 单条流水线执行结果.
[BestPrice price is 227.53480147033423, LetsSaveBig price is 200.89398407500244, MyFavoriteShop price is 161.14747297059597, BuyItAll price is 155.9041805933185]
one pipeline composed CompletableFuture done in 4004 msecs

组合两条流水线

public List<String> findPricesFuture(String product) {
    List<CompletableFuture<String>> priceFutures =
        shops.stream()
            .map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is "
                + shop.getPrice(product), executor)) // 指定线程池执行生产者方法,如果不配置此选项,
            .collect(Collectors.toList());  // 得到一个List>,列表中的每个CompletableFuture对象在计算完成后都包含商店的String类型的名称。

    // 要得到List,需要等待所有的future执行完毕,将其包含的值抽取出来,填充到列表中才能返回。使用join方法获取CompletableFuture包含的值.
    List<String> prices = priceFutures.stream()
        .map(CompletableFuture::join) // 等待所有异步操作结束
        .collect(Collectors.toList());
    return prices;
  }
  // 组合两条流水线执行结果
  [BestPrice price is 171.10524235618578, LetsSaveBig price is 168.59369176671822, MyFavoriteShop price is 174.79155890558252, BuyItAll price is 154.82955565763797]
    // 书上显示是2000ms左右,这里貌似跟直接并行流差不多.
composed CompletableFuture done in 1006 msecs

多条流水线组合异步+同步+Stream组合

public List<String> findPricesFuture(String product) {
        List<CompletableFuture<String>> priceFutures = findPricesStream(product)
                .collect(Collectors.<String>>toList());

        return priceFutures.stream()
                // 等待流中的所有Future执行完毕,并提取各自的返回值
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
    }

public Stream<CompletableFuture<String>> findPricesStream(String product) {

        return shops.stream()
            // 以异步方式取得每个shop中指定产品的原始价格, 返回值 Stream>
                .map(shop -> CompletableFuture.supplyAsync(() -> shop.getPrice(product), executor))
                // 不需要异步, 因为只是price+折扣字符串->Quota对象,返回 Stream>
                .map(future -> future.thenApply(Quote::parse)) // 取future中的string进行解析.
                // 使用另一个异步任务构造期望的Future,申请折扣
                .map(future -> future.thenCompose(quote -> CompletableFuture.supplyAsync(() -> Discount.applyDiscount(quote), executor)));
    }
    
// 执行时间
[BestPrice price is 204.78, LetsSaveBig price is 190.85, MyFavoriteShop price is 128.92, BuyItAll price is 140.31, ShopEasy price is 166.1]
composed CompletableFuture done in 2009 msecs

Predicate 合并
甚至可以用and()、or()和xor()逻辑函数来合并Predicate,
例如要找到所有以J开始,长度为四个字母的名字,你可以合并两个Predicate并传入

Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
    .filter(startsWithJ.and(fourLetterLong))

自定义filter

public static void filter(List names, Predicate condition) {
    names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
        System.out.println(name + " ");
    });
}

综合用法

 private List<String> afterJava8(List<Dish> dishList) {
    return dishList.stream()
            .filter(d -> d.getCalories() < 400)  //筛选出卡路里小于400的菜肴
            .sorted(comparing(Dish::getCalories))  //根据卡路里进行排序
            .map(Dish::getName)  //提取菜肴名称
            .collect(Collectors.toList()); //转换为List
}
//对数据库查询到的菜肴根据菜肴种类进行分类,返回一个Map<Type, List<Dish>>的结果
private static Map<Type, List<Dish>> afterJdk8(List<Dish> dishList) {
    return dishList.stream().collect(groupingBy(Dish::getType));
}

文档:
java8-tutorial
http://blog.didispace.com/books/java8-tutorial/ch1.html
30 seconds of java8
https://github.com/biezhi/30-seconds-of-java8#chunk

你可能感兴趣的:(java8)