Stream流式惰性计算

1.生成斐波那契数列(Stream基本使用)

要求是编写一个能输出斐波拉契数列(Fibonacci)的LongStream

因为Java的范型不支持基本类型,所以我们无法用Stream<long>这样的类型,会发生编译错误。为了保存long,只能使用Stream<Long>,但这样会产生频繁的装箱、拆箱操作。

为了提高效率,Java标准库提供了IntStream、LongStream和DoubleStream这三种使用基本类型的Stream,它们的使用方法和范型Stream没有大的区别

public class Main {
	public static void main(String[] args) throws IOException {
		LongStream fib = LongStream.generate(new FibSupplier());
		// 打印Fibonacci数列:1,1,2,3,5,8,13,21...
		fib.limit(10).forEach(System.out::println);
	}
}

class FibSupplier implements LongSupplier {
    long first = 0;
    long second = 1;
    public long getAsLong() {
        long p = second;
        second += first;
        first = p;
        return first;
    }
}

2. String 转换为LocalDate (map使用)

正常转换:


import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
/**
 * 	String 类型转为 LocalDate类型
 *
 */
public class DemoDate {
	public static void main(String[] args) {
		String date1 = "2021-06-13";
		DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date2 = LocalDate.parse(date1, fmt);
		System.out.println(date1);
		System.out.println(date2);
	}
}

case1:不指明format

 String[] strs = new String[]{"2021-01-02", "2021-07-02"};
 Stream.of(strs).map(LocalDate::parse).forEach(System.out::println);

case2: 指明format:

匿名函数版本:
String[] strs = new String[]{"2021-01-02", "2021-07-02"};
Stream.of(strs).map(str -> {
     return LocalDate.parse(str, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
}).forEach(System.out::println);

优化版本:     
String[] strs = new String[]{"2021-01-02", "2021-07-02"};
Stream.of(strs).map(str -> LocalDate.parse(str, DateTimeFormatter.ofPattern("yyyy-MM-dd"))).forEach(System.out::println);

3.从一组给定的LocalDate中过滤掉工作日,得到休息日(filter 使用)

filter()除了常用于数值外,也可应用于任何Java对象。
例如,从一组给定的LocalDate中过滤掉工作日,以便得到休息日:

public class Main {
    public static void main(String[] args) {
        Stream.generate(new LocalDateSupplier())
                .limit(31) // 调用31次LocalDateSupplier.get方法,得到31个ldt
                .filter(ldt -> ldt.getDayOfWeek() == DayOfWeek.SATURDAY || ldt.getDayOfWeek() == DayOfWeek.SUNDAY) // 过滤掉工作日
                .forEach(System.out::println);
    }
}

class LocalDateSupplier implements Supplier<LocalDate> {
    LocalDate start = LocalDate.of(2021, 1, 1);// 起始日期2021.1.1
    int n = -1;
    public LocalDate get() {
        n++;
        return start.plusDays(n); // 起始日期+步进增量n
    }
}

3. reduce计算

4. 输出为集合或者数组

输出为List、Set:

一组String先过滤掉空字符串,然后把非空字符串保存到List中

public class Main {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("Apple", "", null, "Pear", "  ", "Orange");
        List<String> list = stream.filter(s -> s != null && !s.isBlank()).collect(Collectors.toList());
        System.out.println(list);
    }
}

把Stream的每个元素收集到List的方法是调用collect()并传入Collectors.toList()对象,它实际上是一个Collector实例,通过类似reduce()的操作,把每个元素添加到一个收集器中(实际上是ArrayList)。

类似的,collect(Collectors.toSet())可以把Stream的每个元素收集到Set中。

输出为数组

把Stream的元素输出为数组和输出为List类似,我们只需要调用toArray()方法,并传入数组的“构造方法”:

List<String> list = List.of("Apple", "Banana", "Orange");
String[] array = list.stream().toArray(String[]::new);

注意到传入的“构造方法”是String[]::new,它的签名实际上是IntFunction<String[]>定义的String[] apply(int),即传入int参数,获得String[]数组的返回值。

输出为map:

如果我们要把Stream的元素收集到Map中,就稍微麻烦一点。因为对于每个元素,添加到Map时需要key和value,因此,我们要指定两个映射函数,分别把元素映射为key和value:

public class Main {
    public static void main(String[] args) {
        Stream<String> stream = Stream.of("APPL:Apple", "MSFT:Microsoft");
        Map<String, String> map = stream
                .collect(Collectors.toMap(
                        // 把元素s映射为key:
                        s -> s.substring(0, s.indexOf(':')),
                        // 把元素s映射为value:
                        s -> s.substring(s.indexOf(':') + 1)));
        System.out.println(map);
    }
}

分组输出

public class Main {
    public static void main(String[] args) {
        List<String> list = List.of("Apple", "Banana", "Blackberry", "Coconut", "Avocado", "Cherry", "Apricots");
        Map<String, List<String>> groups = list.stream()
                .collect(Collectors.groupingBy(s -> s.substring(0, 1), Collectors.toList()));
        System.out.println(groups);
    }
}

分组输出使用Collectors.groupingBy(),它需要提供两个函数:
一个是分组的key,这里使用s -> s.substring(0, 1),表示只要首字母相同的String分到一组,
第二个是分组的value,这里直接使用Collectors.toList(),表示输出为List,上述代码运行结果如下:

{
    A=[Apple, Avocado, Apricots],
    B=[Banana, Blackberry],
    C=[Coconut, Cherry]
}

可见,结果一共有3组,按"A",“B”,"C"分组,每一组都是一个List。

Stream提供的常用操作:

转换操作:map()filter()sorted()distinct();

合并操作:concat()flatMap();

并行处理:parallel();

聚合操作:reduce()collect()count()max()min()sum()average();

其他操作:allMatch(), anyMatch(), forEach()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用流(Stream)编程具有以下优点和缺点: 优点: 1. 简洁和可读性:使用流编程可以通过一系列的操作来处理数据流,使代码更加简洁、易读和易于理解。这使得代码更具可维护性,减少了冗余的代码。 2. 延迟计算流式编程支持延迟计算,只有在需要时才会触发实际的计算。这种惰性计算的特性可以提高性能,尤其是当处理大量数据或复杂计算时。 3. 可组合性:流的操作可以被组合在一起形成一个流水线,使得代码更具可组合性。通过将多个操作连接起来,可以轻松构建复杂的数据处理流程。 4. 并行处理:由于流操作是相互独立的,因此可以很容易地进行并行处理。这使得在多核或分布式系统中对数据进行高效处理成为可能。 缺点: 1. 学习曲线:对于不熟悉流编程的开发人员来说,学习和理解流的概念和操作可能需要一些时间和学习成本。 2. 难以调试:由于流式操作是惰性计算的,当出现错误时,定位问题的源头可能会比较困难。调试流式代码可能需要更多的工作。 3. 不适用于所有场景:虽然流在处理大量数据或需要复杂计算时非常有效,但对于简单的数据处理任务可能会显得过于冗余。在这种情况下,使用流可能会增加额外的复杂性和开销。 综上所述,使用流编程可以带来简洁、可读性强、可维护性好的代码,而且支持延迟计算和并行处理。然而,对于不熟悉流编程的开发人员来说,学习和调试可能会有一些挑战,而且在某些简单的场景下可能会显得过度复杂。因此,在选择使用流时需要根据具体情况进行权衡。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值