一、Java8中的Stream
Java8之所以被广大的Java爱好者所喜爱,是因为它提供了一系列的关于集合的Stream操作。集合API是Java API中最重要的部分。基本上每一个java程序都离不开集合。尽管很重要,但是现有的集合处理在很多方面都无法满足需要。
一个原因是,许多其他的语言或者类库以声明的方式来处理特定的数据模型,比如SQL语言,你可以从表中查询,按条件过滤数据,并且以某种形式将数据分组,而不必需要了解查询是如何实现的——数据库帮你做所有的脏活。这样做的好处是你的代码很简洁。很遗憾,Java没有这种好东西,你需要用控制流程自己实现所有数据查询的底层的细节。
其次是你如何有效地处理包含大量数据的集合。理想情况下,为了加快处理过程,你会利用多核架构。但是并发程序不太好写,而且很容易出错。
Stream API很好的解决了这两个问题。它抽象出一种叫做流的东西让你以声明的方式处理数据,更重要的是,它还实现了多线程:帮你处理底层诸如线程、锁、条件变量、易变变量等等。
说了这么多,到底什么是流?通俗地讲,你可以认为是支持类似数据库操作的“花哨的迭代器”。技术上讲,它是从某个数据源获得的支持聚合操作的元素序列。
下面着重介绍一下正式的定义:
元素序列:针对特定元素类型的有序集合流提供了一个接口。但是流不会存储元素,只会根据要求对其做计算。
数据源:流所用到的数据源来自集合、数组或者I/O。
聚合操作:流支持类似数据库的操作以及函数式语言的基本操作,比如filter、map、reduce、findFirst、allMatch、sorted等待。
此外,流操作还有两种额外的基础属性根据不同的集合区分:
管道连接:许多流操作返回流本身,这种操作可以串联成很长的管道,这种方式更加有利于像延迟加载,短路,循环合并等操作。
内部迭代器:不像集合依赖外部迭代器,流操作在内部帮你实现了迭代器。
流接口在java.util.stream.Stream定义了许多操作,这些可以分为以下两类:像filter、sorted和map一样的可以被连接起来形成一个管道的操作。
像collect、findFirst和allMatch一样的终止管道并返回数据的操作。
可以被连接起来的操作被称为中间操作,它们能被连接起来是因为都返回流。中间操作都“很懒”并且可以被优化。终止一个流管道的操作被叫做结束操作,它们从流管道返回像List,Integer或者甚至是void等非流类型的数据。
下面我们介绍一下流里面的一些方法,完整的方法列表可以在java.util.stream.Stream找到。
Filter:有好几个方法可以用来从流里面过滤出元素:
filter:通过传递一个预期匹配的对象作为参数并返回一个包含所有匹配到的对象的流。
distinct:返回包含唯一元素的流(唯一性取决于元素相等的实现方式)。
limit:返回一个特定上限的流。
skip:返回一个丢弃前n个元素的流。
Matching:匹配是一个判断是否匹配到给定属性的普遍的数据处理模式。
Finding:提供了像findFirst和findAny等从流中取出任意的元素。它们能与像filter方法相连接。findFirst和findAny都返回一个可选对象。
Mapping:流支持映射方法,传递一个函数对象作为方法,把流中的元素转换成另一种类型。这种方法应用于单个元素,将其映射成新元素。
Reducing:把数据源中的所有元素结合起来提供单一的值。
Collectors:目前为止你所了解的方法都是返回另一个流或者一个像boolean,int类型的值,或者返回一个可选对象。相比之下,collect方法是一个结束操作,它可以使流里面的所有元素聚集到汇总结果。
传递给collect方法参数是一个java.util.stream.Collector类型的对象。Collector对象实际上定义了一个如何把流中的元素聚集到最终结果的方法。最开始,工厂方法Collectors.toList()被用来返回一个描述了如何把流转变成一个List的Collector对象。后来Collectors类又内建了很多相似的collectors变量。
二、实例
通过一个实例来对比下Java8之前的集合操作:
public class Demo { private int id; private String name; private double invoice; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getInvoice() { return invoice; } public void setInvoice(double invoice) { this.invoice = invoice; } }
public class StreamDemo { private static Logger logger = LoggerFactory.getLogger(StreamDemo.class); public static void main(String[] args){ List<Integer> idList1 = getIdsWithOldWay(convertData()); logger.info("以普通的Java实现方式:list={}",idList1); List<Integer> idList2 = getIdsWithStream(convertData()); logger.info("以Java8的实现方式:list={}",idList2); boolean flag = idList1.equals(idList2); logger.info("比较两种方式:compareResult={}",flag); } private static List<Integer> getIdsWithOldWay(List<Demo> demoList){ List<Integer> idList = Lists.newArrayList(); List<Demo> demos = Lists.newArrayList(); for(Demo demo : demoList){ if("张三丰".equals(demo.getName())){ if(demo.getInvoice() > 0.00){ demos.add(demo); } } } Collections.sort(demos, new Comparator<Demo>() { @Override public int compare(Demo demo1, Demo demo2) { return Double.compare(demo1.getInvoice(),demo2.getInvoice()); } }); for(Demo demo : demos){ idList.add(demo.getId()); } return idList.subList(0,3); } private static List<Integer> getIdsWithStream(List<Demo> demoList){ return demoList.stream() .filter(demo -> "张三丰".equals(demo.getName())) .filter(demo -> demo.getInvoice() > 0.00) .sorted(Comparator.comparingDouble(Demo :: getInvoice)) .map(Demo :: getId) .limit(3) .collect(Collectors.toList()); } private static List<Demo> convertData(){ List<Demo> demoList = Lists.newArrayList(); Demo demo1 = new Demo(); demo1.setId(1); demo1.setName("张三丰"); demo1.setInvoice(0.03); demoList.add(demo1); Demo demo2 = new Demo(); demo2.setId(2); demo2.setName("张三丰"); demo2.setInvoice(0.02); demoList.add(demo2); Demo demo3 = new Demo(); demo3.setId(3); demo3.setName("张三丰"); demo3.setInvoice(0.01); demoList.add(demo3); Demo demo4 = new Demo(); demo4.setId(4); demo4.setName("张三丰"); demo4.setInvoice(0.06); demoList.add(demo4); Demo demo5 = new Demo(); demo5.setId(5); demo5.setName("张三丰"); demo5.setInvoice(0.05); demoList.add(demo5); Demo demo6 = new Demo(); demo6.setId(6); demo6.setName("张三丰"); demo6.setInvoice(0.04); demoList.add(demo6); return demoList; } }
三、运行结果
14:27:26.518 [main] INFO c.pajk.docplatformmanager.StreamDemo - 以普通的Java实现方式:list=[3, 2, 1]
14:27:26.618 [main] INFO c.pajk.docplatformmanager.StreamDemo - 以Java8的实现方式:list=[3, 2, 1]
14:27:26.618 [main] INFO c.pajk.docplatformmanager.StreamDemo - 比较两种方式:compareResult=true
相关推荐
Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了流的概念,流是作为一种对数据执行...
Java的IO流是Java编程语言中的重要组成部分,它主要用于数据的输入和输出操作。在Java中,IO流被设计为处理任何类型的数据,包括字符、字节甚至对象。本练习旨在帮助初学者理解和掌握Java IO流的基础知识。 一、IO...
Java 中文件 IO 流 Java 中文件 IO 流是指 Java 语言中对文件的输入输出操作,通过定义文件流来实现文件的读写...在 Java 中,文件 IO 流操作是非常重要的,掌握文件 IO 流操作可以帮助我们更好地处理文件相关的任务。
3. **缓冲流**:为了提高性能,Java提供了缓冲流,如`BufferedReader`和`BufferedWriter`,它们在底层字节或字符流之上添加了一个缓冲区,减少了对底层资源的频繁访问。 4. **过滤流**:过滤流是在已存在的流基础上...
Java 8最大的亮点之一就是引入了Lambda表达式,它允许开发者以更简洁的方式处理函数式编程任务。Lambda可以看作是一段没有名字的匿名函数,可以用作参数或返回值。例如,`Runnable r = () -> System.out.println(...
Java分布式IP限流和防止恶意IP攻击方案 本文主要介绍了Java分布式IP限流和防止恶意IP攻击方案,通过示例代码详细介绍了限流和防止恶意IP攻击的实现方式。 一、分布式IP限流 分布式IP限流是分布式系统设计中经常...
Java的设计理念之一就是让程序员能够通过一套统一且灵活的API来处理各种I/O需求。 #### 流的概念及其分类 在Java中,**流**(Stream)是用于描述数据从一个地方到另一个地方的移动方式。根据数据流动的方向,流被...
Java工作流源码是用于实现工作流自动化的一种编程资源,它可以帮助开发者构建高效、可扩展的企业级业务流程管理系统。在Java领域,工作流通常涉及到BPM(Business Process Management)技术,用于管理和优化组织内的...
通过学习和理解这些知识点,初学者能够熟练地使用Java I/O流进行各种数据操作,无论是简单的文件读写,还是复杂的网络数据交换,都能游刃有余。在实际编程中,根据需求选择合适的流类型和组合,能有效地提升程序的...
7. **可移植性**:由于Java的“一次编写,到处运行”特性,基于Java的工作流系统可以在不同的操作系统和硬件平台上运行,这对于企业的IT基础设施具有很高的灵活性。 在实际应用中,Java工作流解决方案可以广泛应用...
Java IO流处理是Java编程中一个非常重要的概念,主要用于数据的输入和输出操作。对于Java初学者来说,理解和掌握IO流的基本使用至关重要。在Java中,流被形象地比喻为数据传输的通道,数据可以从一个源头(如文件、...
在这个实验中,你会学习到如何在Java中使用位操作和I/O流来实现一个简单的流密码系统。实际应用中,流密码的安全性取决于密钥生成器的复杂性和密钥的长度,因此在设计时需要确保足够的安全性。同时,也要注意防止...
这个简单的例子展示了Java输入输出流的基本用法,实际应用中,我们可以根据需求选择不同的流类型和操作方式,例如处理网络数据传输、内存缓冲、压缩解压等复杂场景。理解并熟练掌握Java的输入输出流,对于进行任何...
理解并熟练运用Java IO流技术是开发Java应用程序的关键,它能够有效地处理数据的读写操作,无论是简单的文本文件还是复杂的网络通信。在实际编程中,根据需求选择适当的流类型,结合处理流进行优化,可以构建出高效...
首先,Java 8的最重要的新特性之一是Lambda表达式。Lambda表达式提供了一种简洁的方式来表示匿名函数,使得代码更加简洁和易读。它们常被用于函数式接口,如Runnable、Comparator等,简化了多线程编程和数据处理。...
流操作通常被组织为流管道,包括源、中间操作和终端操作。 8. 并发API的改进(Concurrency API Improvements): Java 8对并发API也进行了大量改进,例如增加了新的并发工具,如CompletableFuture和Phaser。这些...
8. **事件驱动编程**:Java的事件驱动模型使得用户界面的交互变得更加简单。例如,当用户点击发送按钮时,会触发相应的事件处理器,执行发送消息的操作。 9. **日志记录**:为了便于调试和问题追踪,开发者可能还...
### Java的IO流操作 #### 一、Java IO流概述 在Java中,输入/输出(Input/Output,简称IO)流是进行数据读写的基础技术。Java的IO流主要包含两大类:字节流(byte stream)和字符流(character stream)。字节流...
1. **Lambda表达式**:Java 8最重要的特性之一就是引入了Lambda表达式,这是一种简洁的匿名函数表示方式,使得编写多线程和函数式编程变得更加简单。Lambda可以被用作方法参数,可以返回一个结果,或者没有结果,...
总的来说,Java的流和文件操作是一个广泛且基础的主题,涵盖了从简单的文件复制到复杂的数据序列化。学习这些概念不仅有助于理解Java I/O系统的工作原理,也是开发高效、可靠应用程序的基础。在实际编程中,开发者...