Java 8实战之读书笔记三:函数式数据处理

本文介绍Java8中的流(Stream)API及其在函数式数据处理中的应用,包括流的基本概念、常用操作如filter、map及reduce,如何创建流,使用流收集数据,以及并行数据处理的技巧。

二、函数式数据处理

第4章 引入流

流是Java API的新成员,它允许你以声明性方式处理数据集合(通过查询语句来表达,而不是临时编写一个实现)。

示例:

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

//为了利用多核架构并行执行这段代码换成.parallelStream()
List<String> lowCaloricDishesName = menu.stream()//.parallelStream()
   .filter(d -> d.getCalories() < 400)
   .sorted(comparing(Dish::getCalories))
   .map(Dish::getName)
   .collect(toList());

把几个基础操作链接起来,来表达复杂的数据处理流水线(在filter后面接上sorted、 map和collect操作,如图所示),同时保持代码清晰可读

172900_m0Zf_3290751.png

流的定义:从支持数据处理操作的源生成的元素序列,流操作具有流水线、内部迭代的特点。

关于内部迭代:

173656_j8oB_3290751.png

注意的是,和迭代器类似,流只能遍历一次。

流的操作分为中间操作、终端操作两种操作。

173905_UjCP_3290751.png

中间/终端操作具体的如下:

174033_EhNN_3290751.png

以下是你应从本章中学到的一些关键概念。
     流是“从支持数据处理操作的源生成的一系列元素”。
     流利用内部迭代:迭代通过filter、 map、 sorted等操作被抽象掉了。
     流操作有两类:中间操作和终端操作。
     filter和map等中间操作会返回一个流,并可以链接在一起。可以用它们来设置一条流水线,但并不会生成任何结果。
     forEach和count等终端操作会返回一个非流的值,并处理流水线以返回结果。
     流中的元素是按需计算的。

第5章 使用流

流的操作:

174459_p3ii_3290751.png

注意的是,强大的归约:reduce

示例:

List<Integer> numbers = Arrays.asList(4, 5, 3, 9);
int sum = numbers.stream().reduce(0, (a, b) -> a + b);
/**
 reduce接受两个参数:
  一个初始值,这里是0;
  一个BinaryOperator<T>来将两个元素结合起来产生一个新值,这里我们用的是
   lambda (a, b) -> a + b。
*/

// Integer类现在有了一个静态的sum方法来对两个数求和
int sum = numbers.stream().reduce(0, Integer::sum);

// 无初始值
// reduce还有一个重载的变体,它不接受初始值,但是会返回一个Optional对象:
Optional<Integer> sum = numbers.stream().reduce((a, b) -> (a + b));

// 另外,还可以通过Integer.max或者.min来获取最大值和最小值
Optional<Integer> max = numbers.stream().reduce(Integer::max);

个人觉得归约是集大成者,第二参数填入不同的表达式就对应着不同的直接方法,如.sum(),.max()等等。

数值范围:(IntStream调用.boxed()把IntStream转化成Stream<Integer>)

    IntStream.rangeClosed(1, 100);

由值创建流

    Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
    stream.map(String::toUpperCase).forEach(System.out::println);
    你可以使用empty得到一个空流,如下所示:
    Stream<String> emptyStream = Stream.empty();

由数组创建流
    int[] numbers = {2, 3, 5, 7, 11, 13};
    int sum = Arrays.stream(numbers).sum();

由文件生成流
    long uniqueWords = 0;
    try(Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())){
        uniqueWords = lines.flatMap(line -> Arrays.stream(line.split(" ")))
            .distinct()
            .count();
    } catch(IOException e){}

由函数生成流:创建无限流
    迭代:Stream.iterate(0, n -> n + 2);

    生成:Stream.generate(Math::random);

    这一章很长,但是很有收获!现在你可以更高效地处理集合了。事实上,流让你可以简洁地表达复杂的数据处理查询。此外,流可以透明地并行化。以下是你应从本章中学到的关键概念。
     Streams API可以表达复杂的数据处理查询。常用的流操作总结在表5-1中。
     你可以使用filter、 distinct、 skip和limit对流做筛选和切片。
     你可以使用map和flatMap提取或转换流中的元素。
     你 可 以 使 用 findFirst 和 findAny 方 法 查 找 流 中 的 元 素 。 你 可 以 用 allMatch 、noneMatch和anyMatch方法让流匹配给定的谓词。
     这些方法都利用了短路:找到结果就立即停止计算;没有必要处理整个流。
     你可以利用reduce方法将流中所有的元素迭代合并成一个结果,例如求和或查找最大元素。
     filter和map等操作是无状态的,它们并不存储任何状态。 reduce等操作要存储状态才能计算出一个值。 sorted和distinct等操作也要存储状态,因为它们需要把流中的所有元素缓存起来才能返回一个新的流。这种操作称为有状态操作。
     流有三种基本的原始类型特化: IntStream、 DoubleStream和LongStream。它们的操作也有相应的特化。
     流不仅可以从集合创建,也可从值、数组、文件以及iterate与generate等特定方法创建。
     无限流是没有固定大小的流。

第6章 用流收集数据

204144_g1wx_3290751.png

204250_qS8C_3290751.png

Collector接口

public interface Collector<T, A, R> {
   Supplier<A> supplier();
   BiConsumer<A, T> accumulator();
   Function<A, R> finisher();
   BinaryOperator<A> combiner();
   Set<Characteristics> characteristics();
}
/**
 本列表适用以下定义。
  T是流中要收集的项目的泛型。
  A是累加器的类型,累加器是在收集过程中用于累积部分结果的对象。
  R是收集操作得到的对象(通常但并不一定是集合)的类型。
*/

以下是你应从本章中学到的关键概念。
     collect是一个终端操作,它接受的参数是将流中元素累积到汇总结果的各种方式(称为收集器)。
     预定义收集器包括将流元素归约和汇总到一个值,例如计算最小值、最大值或平均值。这些收集器总结在表6-1中。
     预定义收集器可以用groupingBy对流中元素进行分组,或用partitioningBy进行分区。
     收集器可以高效地复合起来,进行多级分组、分区和归约。
     你可以实现Collector接口中定义的方法来开发你自己的收集器。

第7章 并行数据处理与性能

高效使用并行流
     如果有疑问,测量。把顺序流转成并行流轻而易举,但却不一定是好事。我们在本节中已经指出,并行流并不总是比顺序流快。此外,并行流有时候会和你的直觉不一致,所以在考虑选择顺序流还是并行流时,第一个也是最重要的建议就是用适当的基准来检查其性能。
     留意装箱。自动装箱和拆箱操作会大大降低性能。 Java 8中有原始类型流(IntStream、LongStream、 DoubleStream)来避免这种操作,但凡有可能都应该用这些流。
     有些操作本身在并行流上的性能就比顺序流差。特别是limit和findFirst等依赖于元素顺序的操作,它们在并行流上执行的代价非常大。例如, findAny会比findFirst性能好,因为它不一定要按顺序来执行。你总是可以调用unordered方法来把有序流变成无序流。那么,如果你需要流中的n个元素而不是专门要前n个的话,对无序并行流调用limit可能会比单个有序流(比如数据源是一个List)更高效。
     还要考虑流的操作流水线的总计算成本。设N是要处理的元素的总数, Q是一个元素通过流水线的大致处理成本,则N*Q就是这个对成本的一个粗略的定性估计。 Q值较高就意味着使用并行流时性能好的可能性比较大。
     对于较小的数据量,选择并行流几乎从来都不是一个好的决定。并行处理少数几个元素的好处还抵不上并行化造成的额外开销。
     要考虑流背后的数据结构是否易于分解。例如, ArrayList的拆分效率比LinkedList高得多,因为前者用不着遍历就可以平均拆分,而后者则必须遍历。另外,用range工厂方法创建的原始类型流也可以快速分解。最后,你将在7.3节中学到,你可以自己实现Spliterator来完全掌控分解过程。
     流自身的特点,以及流水线中的中间操作修改流的方式,都可能会改变分解过程的性能。例如,一个SIZED流可以分成大小相等的两部分,这样每个部分都可以比较高效地并行处理,但筛选操作可能丢弃的元素个数却无法预测,导致流本身的大小未知。
     还要考虑终端操作中合并步骤的代价是大是小(例如Collector中的combiner方法) 。如果这一步代价很大,那么组合每个子流产生的部分结果所付出的代价就可能会超出通过并行流得到的性能提升。

 

内容概要:本文介绍了ENVI Deep Learning V1.0的操作教程,重点讲解了如何利用ENVI软件进行深度学习模型的训练与应用,以实现遥感图像中特定目标(如集装箱)的自动提取。教程涵盖了从数据准备、标签图像创建、模型初始化与训练,到执行分类及结果优化的完整流程,并介绍了精度评价与通过ENVI Modeler实现一键化建模的方法。系统基于TensorFlow框架,采用ENVINet5(U-Net变体)架构,支持通过点、线、面ROI或分类图生成标签数据,适用于多/高光谱影像的单一类别特征提取。; 适合人群:具备遥感图像处理基础,熟悉ENVI软件操作,从事地理信息、测绘、环境监测等相关领域的技术人员或研究人员,尤其是希望将深度学习技术应用于遥感目标识别的初学者与实践者。; 使用场景及目标:①在遥感影像中自动识别和提取特定地物目标(如车辆、建筑、道路、集装箱等);②掌握ENVI环境下深度学习模型的训练流程与关键参数设置(如Patch Size、Epochs、Class Weight等);③通过模型调优与结果反馈提升分类精度,实现高效自动化信息提取。; 阅读建议:建议结合实际遥感项目边学边练,重点关注标签数据制作、模型参数配置与结果后处理环节,充分利用ENVI Modeler进行自动化建模与参数优化,同时注意软硬件环境(特别是NVIDIA GPU)的配置要求以保障训练效率。
内容概要:本文系统阐述了企业新闻发稿在生成式引擎优化(GEO)时代下的全渠道策略与效果评估体系,涵盖当前企业传播面临的预算、资源、内容与效果评估四大挑战,并深入分析2025年新闻发稿行业五大趋势,包括AI驱动的智能化转型、精准化传播、首发内容价值提升、内容资产化及数据可视化。文章重点解析央媒、地方官媒、综合门户和自媒体四类媒体资源的特性、传播优势与发稿策略,提出基于内容适配性、时间节奏、话题设计的策略制定方法,并构建涵盖品牌价值、销售转化与GEO优化的多维评估框架。此外,结合“传声港”工具实操指南,提供AI智能投放、效果监测、自媒体管理与舆情应对的全流程解决方案,并针对科技、消费、B2B、区域品牌四大行业推出定制化发稿方案。; 适合人群:企业市场/公关负责人、品牌传播管理者、数字营销从业者及中小企业决策者,具备一定媒体传播经验并希望提升发稿效率与ROI的专业人士。; 使用场景及目标:①制定科学的新闻发稿策略,实现从“流量思维”向“价值思维”转型;②构建央媒定调、门户扩散、自媒体互动的立体化传播矩阵;③利用AI工具实现精准投放与GEO优化,提升品牌在AI搜索中的权威性与可见性;④通过数据驱动评估体系量化品牌影响力与销售转化效果。; 阅读建议:建议结合文中提供的实操清单、案例分析与工具指南进行系统学习,重点关注媒体适配性策略与GEO评估指标,在实际发稿中分阶段试点“AI+全渠道”组合策略,并定期复盘优化,以实现品牌传播的长期复利效应。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值