必知的技术知识:java8之stream

简介: 必知的技术知识:java8之stream

lambda表达式是stream的基础,初学者建议先学习lambda表达式,


1.初识stream


先来一个总纲:


东西就是这么多啦,stream是java8中加入的一个非常实用的功能,最初看时以为是io中的流(其实一点关系都没有),让我们先来看一个小例子感受一下:


@Before


public void init() {


random = new Random();


stuList = new ArrayList() {


{


for (int i = 0; i < 100; i++) {


add(new Student("student" + i, random.nextInt(50) + 50));


}


}


};


}


public class Student {


private String name;


private Integer score;


//-----getters and setters-----


}


//1列出班上超过85分的学生姓名,并按照分数降序输出用户名字


@Test


public void test1() {


List studentList = stuList.stream()


.filter(x->x.getScore()>85)


.sorted(Comparator.comparing(Student::getScore).reversed())


.map(Student::getName)


.collect(Collectors.toList());


System.out.println(studentList);


}


列出班上分数超过85分的学生姓名,并按照分数降序输出用户名字,在java8之前我们需要三个步骤:


1)新建一个List newList,在for循环中遍历stuList,将分数超过85分的学生装入新的集合中


2)对于新的集合newList进行排序操作


3)遍历打印newList


这三个步骤在java8中只需要两条语句,如果紧紧需要打印,不需要保存新生产list的话实际上只需要一条,是不是非常方便。


2.stream的特性


我们首先列出stream的如下三点特性,在之后我们会对照着详细说明


1.stream不存储数据


2.stream不改变源数据


3.stream的延迟执行特性


通常我们在数组或集合的基础上创建stream,stream不会专门存储数据,对stream的操作也不会影响到创建它的数组和集合,对于stream的聚合、消费或收集操作只能进行一次,再次操作会报错,如下代码:


@Test


public void test1(){


Stream stream = Stream.generate(()->"user").limit(20);


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


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


}


程序在正常完成一次打印工作后报错。


stream的操作是延迟执行的,在列出班上超过85分的学生姓名例子中,在collect方法执行之前,filter、sorted、map方法还未执行,只有当collect方法执行时才会触发之前转换操作


看如下代码:


public boolean filter(Student s) {


System.out.println("begin compare");


return s.getScore() > 85;


}


@Test


public void test() {


Stream stream = Stream.of(stuArr).filter(this::filter);


System.out.println("split-------------------------------------");


List studentList = stream.collect(toList());


}


我们将filter中的逻辑抽象成方法,在方法中加入打印逻辑,如果stream的转换操作是延迟执行的,那么split会先打印,否则后打印,代码运行结果为


可见stream的操作是延迟执行的。


TIP:


当我们操作一个流的时候,并不会修改流底层的集合(即使集合是线程安全的),如果想要修改原有的集合,就无法定义流操作的输出。


由于stream的延迟执行特性,在聚合操作执行前修改数据源是允许的。


List wordList;


@Before


public void init() {


wordList = new ArrayList() {


{


add("a");


add("b");


add("c");


add("d");


add("e");


add("f");


add("g");


}


};


}


/


延迟执行特性,在聚合操作之前都可以添加相应元素


/


@Test


public void test() {


Stream words = wordList.stream();


wordList.add("END");


long n = words.distinct().count();


System.out.println(n);


}


最后打印的结果是8


如下代码是错误的


/


延迟执行特性,会产生干扰


nullPointException


/


@Test


public void test2(){


Stream words1 = wordList.stream();


words1.forEach(s -> {


System.out.println("s->"+s);


if (s.length() < 4) {


System.out.println("select->"+s);


wordList.remove(s);


System.out.println(wordList);


}


});


}


结果报空指针异常


3.创建stream


1)通过数组创建


/**


通过数组创建流


/


@Test


public void testArrayStream(){


//1.通过Arrays.stream


//1.1基本类型


int【】 arr = new int【】{1,2,34,5};


IntStream intStream = Arrays.stream(arr);


//1.2引用类型


Student【】 studentArr = new Student【】{new Student("s1",29),new Student("s2",27)};


Stream studentStream = Arrays.stream(studentArr);


//2.通过Stream.of


Stream stream1 = Stream.of(1,2,34,5,65);


//注意生成的是int【】的流


Stream[span style="color: rgba(0, 0, 255, 1)">int【】> stream2 = Stream.of(arr,arr);


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


}


2)通过集合创建流


/**


通过集合创建流


/


@Test


public void testCollectionStream(){


List strs = Arrays.asList("11212","dfd","2323","dfhgf");


//创建普通流


Stream stream = strs.stream();


//创建并行流


Stream stream1 = strs.parallelStream();


}


3)创建空的流


@Test


public void testEmptyStream(){


//创建一个空的stream


Stream stream = Stream.empty();


}


4)创建无限流


@Test


public void testUnlimitStream(){


//创建无限流,通过limit提取指定大小


Stream.generate(()->"number"+new Random().nextInt()).limit(100).forEach(System.out::println);


Stream.generate(()->new Student("name",10)).limit(20).forEach(System.out::println);


}


5)创建规律的无限流


/**


产生规律的数据


/


@Test


public void testUnlimitStream1(){


Stream.iterate(0,x->x+1).limit(10).forEach(System.out::println);


Stream.iterate(0,x->x).limit(10).forEach(System.out::println);


//Stream.iterate(0,x->x).limit(10).forEach(System.out::println);与如下代码意思是一样的


Stream.iterate(0, UnaryOperator.identity()).limit(10).forEach(System.out::println);


}


4.对stream的操作


1)最常使用


map:转换流,将一种类型的流转换为另外一种流


/**


map把一种类型的流转换为另外一种类型的流


将String数组中字母转换为大写


/


@Test


public void testMap() {


String【】 arr = new String【】{"yes", "YES", "no", "NO"};


Arrays.stream(arr).map(x -> x.toLowerCase()).forEach(System.out::println);


}


filter:过滤流,过滤流中的元素


@Test


public void testFilter(){


Integer【】 arr = new Integer【】{1,2,3,4,5,6,7,8,9,10};


Arrays.stream(arr).filter(x->x>3&&x<8).forEach(System.out::println);


}


flapMap:拆解流,将流中每一个元素拆解成一个流


/


flapMap:拆解流


/


@Test


public void testFlapMap1() {


String【】 arr1 = {"a", "b", "c", "d"};


String【】 arr2 = {"e", "f", "c", "d"};


String【】 arr3 = {"h", "j", "c", "d"};


// Stream.of(arr1, arr2, arr3).flatMap(x -> Arrays.stream(x)).forEach(System.out::println);


Stream.of(arr1, arr2, arr3).flatMap(Arrays::stream).forEach(System.out::println);


}


sorted:对流进行排序


String【】 arr1 = {"abc","a","bc","abcd"};


/


Comparator.comparing是一个键提取的功能


以下两个语句表示相同意义


/


@Test


public void testSorted1_(){


/**


按照字符长度排序


/


Arrays.stream(arr1).sorted((x,y)->{


if (x.length()>y.length())


return 1;


else if (x.length()[span style="color: rgba(0, 0, 0, 1)">y.length())


return -1;


else


return 0;


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


Arrays.stream(arr1).sorted(Comparator.comparing(String::length)).forEach(System.out::println);


}


/**


倒序


reversed(),java8泛型推导的问题,所以如果comparing里面是非方法引用的lambda表达式就没办法直接使用reversed()


Comparator.reverseOrder():也是用于翻转顺序,用于比较对象(Stream里面的类型必须是可比较的)


Comparator. naturalOrder():返回一个自然排序比较器,用于比较对象(Stream里面的类型必须是可比较的)


/


@Test


public void testSorted2(){


Arrays.stream(arr1).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);


Arrays.stream(arr1).sorted(Comparator.reverseOrder()).forEach(System.out::println);


Arrays.stream(arr1).sorted(Comparator.naturalOrder()).forEach(System.out::println);


}


/*


thenComparing


先按照首字母排序


之后按照String的长度排序


*/


@Test


public void testSorted3(){


Arrays.stream(arr1).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEach(System.out::println);


}


public char com1(String x){


return x.charAt(0);


}


2)提取流和组合流


@Before


public void init(){


arr1 = new String【】{"a","b","c","d"};


arr2 = new String【】{"d","e","f","g"};


arr3 = new String【】{"i","j","k","l"};


}


/


limit,限制从流中获得前n个数据


/


@Test


public void testLimit(){


Stream.iterate(1,x->x+2).limit(10).forEach(System.out::println);


}


/


skip,跳过前n个数据


/


@Test


public void testSkip(){


// Stream.of(arr1).skip(2).limit(2).forEach(System.out::println);


Stream.iterate(1,x->x+2).skip(1).limit(5).forEach(System.out::println);


}


/


可以把两个stream合并成一个stream(合并的stream类型必须相同)


只能两两合并


*/


@Test


public void testConcat(){


Stream stream1 = Stream.of(arr1);


Stream stream2 = Stream.of(arr2);


Stream.concat(stream1,stream2).distinct().forEach(System.out::println);


}


3)聚合操作


@Before


public void init(){


arr = new String【】{"b","ab","abc","abcd","abcde"};


}


/


max、min


最大最小值


/


@Test


public void testMaxAndMin(){


Stream.of(arr).max(Comparator.comparing(String::length)).ifPresent(System.out::println);


Stream.of(arr).min(Comparator.comparing(String::length)).ifPresent(System.out::println);


}


/**


count


计算数量


/


@Test


public void testCount(){


long count = Stream.of(arr).count();


System.out.println(count);


}


/


findFirst


查找第一个


*/


@Test


public void testFindFirst(){


//代码效果参考:http://www.lyjsj.net.cn/wz/art_24105.html

String str = Stream.of(arr).parallel().filter(x->x.length()>3).findFirst().orElse("noghing");

System.out.println(str);


}


/


findAny


找到所有匹配的元素


对并行流十分有效


只要在任何片段发现了第一个匹配元素就会结束整个运算


/


@Test


public void testFindAny(){


Optional optional = Stream.of(arr).parallel().filter(x->x.length()>3).findAny();


optional.ifPresent(System.out::println);


}


/**


anyMatch


是否含有匹配元素


/


@Test


public void testAnyMatch(){


Boolean aBoolean = Stream.of(arr).anyMatch(x->x.startsWith("a"));


System.out.println(aBoolean);


}


@Test


public void testStream1() {


Optional optional = Stream.of(1,2,3).filter(x->x>1).reduce((x,y)->x+y);


System.out.println(optional.get());


}


4)Optional类型


通常聚合操作会返回一个Optional类型,Optional表示一个安全的指定结果类型,所谓的安全指的是避免直接调用返回类型的null值而造成空指针异常,调用optional.ifPresent()可以判断返回值是否为空,或者直接调用ifPresent(Consumer consumer)在结果部位空时进行消费操作;调用optional.get()获取返回值。通常的使用方式如下:


@Test


public void testOptional() {


List list = new ArrayList() {


{


a

相关文章
|
16天前
|
JSON 前端开发 JavaScript
java-ajax技术详解!!!
本文介绍了Ajax技术及其工作原理,包括其核心XMLHttpRequest对象的属性和方法。Ajax通过异步通信技术,实现在不重新加载整个页面的情况下更新部分网页内容。文章还详细描述了使用原生JavaScript实现Ajax的基本步骤,以及利用jQuery简化Ajax操作的方法。最后,介绍了JSON作为轻量级数据交换格式在Ajax应用中的使用,包括Java中JSON与对象的相互转换。
32 1
|
24天前
|
SQL 监控 Java
技术前沿:Java连接池技术的最新发展与应用
本文探讨了Java连接池技术的最新发展与应用,包括高性能与低延迟、智能化管理和监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,为开发者提供了一份详尽的技术指南。
31 7
|
26天前
|
移动开发 前端开发 Java
过时的Java技术盘点:避免在这些领域浪费时间
【10月更文挑战第14天】 在快速发展的Java生态系统中,新技术层出不穷,而一些旧技术则逐渐被淘汰。对于Java开发者来说,了解哪些技术已经过时是至关重要的,这可以帮助他们避免在这些领域浪费时间,并将精力集中在更有前景的技术上。本文将盘点一些已经或即将被淘汰的Java技术,为开发者提供指导。
51 7
|
21天前
|
SQL Java 数据库连接
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,有效减少连接开销,提升访问效率。本文介绍了连接池的工作原理、优势及实现方法,并提供了HikariCP的示例代码。
36 3
|
22天前
|
SQL 监控 Java
Java连接池技术的最新发展,包括高性能与低延迟、智能化管理与监控、扩展性与兼容性等方面
本文探讨了Java连接池技术的最新发展,包括高性能与低延迟、智能化管理与监控、扩展性与兼容性等方面。同时,结合最佳实践,介绍了如何选择合适的连接池库、合理配置参数、使用监控工具及优化数据库操作,以实现高效稳定的数据库访问。示例代码展示了如何使用HikariCP连接池。
12 2
|
24天前
|
Java 数据库连接 数据库
优化之路:Java连接池技术助力数据库性能飞跃
在Java应用开发中,数据库操作常成为性能瓶颈。频繁的数据库连接建立和断开增加了系统开销,导致性能下降。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接,显著减少连接开销,提升系统性能。文章详细介绍了连接池的优势、选择标准、使用方法及优化策略,帮助开发者实现数据库性能的飞跃。
27 4
|
21天前
|
Java 数据库连接 数据库
深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能
在Java应用开发中,数据库操作常成为性能瓶颈。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接、减少连接建立和断开的开销,从而显著提升系统性能。文章介绍了连接池的优势、选择和使用方法,以及优化配置的技巧。
22 1
|
21天前
|
算法 Java 数据库连接
Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性
本文详细介绍了Java连接池技术,从基础概念出发,解析了连接池的工作原理及其重要性。连接池通过复用数据库连接,显著提升了应用的性能和稳定性。文章还展示了使用HikariCP连接池的示例代码,帮助读者更好地理解和应用这一技术。
35 1
|
24天前
|
SQL Java 数据库连接
打破瓶颈:利用Java连接池技术提升数据库访问效率
在Java应用中,数据库访问常成为性能瓶颈。连接池技术通过预建立并复用数据库连接,避免了频繁的连接建立和断开,显著提升了数据库访问效率。常见的连接池库包括HikariCP、C3P0和DBCP,它们提供了丰富的配置选项和强大的功能,帮助优化应用性能。
44 2
|
24天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。