必知的技术知识: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

相关文章
|
2天前
|
XML Java 数据格式
必知的技术知识:java基础73dom4j修改xml里面的内容(网页知识)
必知的技术知识:java基础73dom4j修改xml里面的内容(网页知识)
|
2天前
|
Java API 数据处理
Java中的lambda表达式与Stream API:高效的函数式编程
Java中的lambda表达式与Stream API:高效的函数式编程
|
2天前
|
XML Java 数据库连接
面试必备!Java核心技术100+面试题
面试必备!Java核心技术100+面试题
|
3天前
|
存储 Java 编译器
技术经验解读:一文带你搞懂java中的变量的定义是什么意思
技术经验解读:一文带你搞懂java中的变量的定义是什么意思
|
3天前
|
SQL 网络协议 Java
技术经验分享:Java不会或做错的面试题总结
技术经验分享:Java不会或做错的面试题总结
11 0
|
3天前
|
Java BI C#
技术笔记:SM4加密算法实现Java和C#相互加密解密
技术笔记:SM4加密算法实现Java和C#相互加密解密
|
3天前
|
Java Maven Python
技术笔记:Lombok介绍、使用方法和总结
技术笔记:Lombok介绍、使用方法和总结
|
3天前
|
机器学习/深度学习 并行计算 搜索推荐
程序技术好文:桶排序算法及其Java实现
程序技术好文:桶排序算法及其Java实现
|
3天前
|
XML 安全 Java
必知的技术知识:Java日志框架:logback详解
必知的技术知识:Java日志框架:logback详解
|
3天前
|
Java 编译器 API
技术经验分享:JAVA8十大新特性详解
技术经验分享:JAVA8十大新特性详解