JAVA1.8新特性Stream流
今天我们来学习⼀下Java 8 的新特新—>Stream流;
Stream流
stream流是Java8的新特性,它也是有关于集合的新api;
Stream 作为 Java 8 的⼀⼤亮点,它与 包⾥的 InputStream 和 OutputStream 是完全不同的概念。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进⾏各种⾮常便利、⾼效的聚合操作,或者⼤批量数据操作;
Stream API 借助于同样新出现的 Lambda 表达式,极⼤的提⾼编程效率和程序可读性;
下⾯我们⽤⼀个例⼦来引⼊Stream流的操作:
Stream流的数据操作特性
这⾥有⼀个集合
List<Integer> list = Arrays.asList(1,2,3,4,5);
我们要写⼀个⽅法偶数,返回⼀个新的list包含结果;
⽤我们以前的⽅法做的话就会⽐较繁琐:
public static void main(String[] args){
List<Integer> list = Arrays.asList(1,2,3,4,5);
System.out.println(exec(list,new Predicate<Integer>(){
@Override
public boolean test(Integer i){
return i %2==0;
}
}));
//System.out.println(exec(list, i -> i % 2 == 0));
}
// 设计模式中,策略模式
public static List<Integer>exec(List<Integer> list, Predicate<Integer> predicate){
List<Integer> list2 =new ArrayList<>();
for(Integer i :list){
st(i)){
list2.add(i);
}
}
return list2;
}
在这⾥我们使⽤了设计模式中的策略模式,将它的处理⽅法拿出来,可以对它的使⽤⽅法进⾏主动的编写,同时我们⽤了⼀个新的模式Predicate,这个模式叫做断⾔模式,顾名思义就是对我们要进⾏的处理进⾏断⾔操作,断定它能进⾏的功能;⽐如上⾯的例⼦就是我们求出了list集合中所有的偶数,那我们如果不想对他进⾏求偶操作呢?⽐如我们想求出集合中所有⼤于三的数据呢?
这个时候我们就可以改变这个断⾔,重新写⼊想要的操作;
System.out.println(exec(list,new Predicate<Integer>(){
@Override
public boolean test(Integer i){
return i >3;
}
在不⽤断⾔模式的时候,我们甚⾄需要新写⼀个⽅法,然后调⽤它,有了断⾔模式,我们就可以主动的给exec这个⽅法传⼊我们想要的策略;
甚⾄我们可以对断⾔进⾏简写;即lambda表达式;
这⾥我们可以看到这个接⼝是⼀个函数式接⼝,就是单⽅法接⼝;所以我们完全可以⽤lambda表达式给他写⼊断⾔;
System.out.println(exec(list,i -> i % 2 == 0);
System.out.println(exec(list,i -> i > 3);
⽤了lambda表达式就⼤⼤减少了我们的代码量;
可是这也是⽐较⿇烦的 ;⽽且在之前我们遍历集合的时候就需要循环,或者 Iterator 迭代器来遍历;这也都是很浪费时间和空间的;
那有没有⼀种⽅法,是我们不⽤调⽤⽅法,直接⽤语句来获得所有的偶数呢?这个时候我们就需要⽤
到jdk1.8的新特性,Stream流,将数组元素变为⼀条数据流,然后对这个数据流进⾏操作,过滤或者收集想要的数据;
特点:
1. Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像⼀个⾼级版本的 Iterator。原始版本的
Iterator,⽤户只能显式地⼀个⼀个遍历元素并对其执⾏某些操作;⾼级版本的 Stream,⽤户只要给出需要对其包含的元素执⾏什么操作,⽐如 “过滤掉长度⼤于 10 的字符串”、“获取每个字符串的⾸字母”等,Stream 会隐式地在内部进⾏遍历,做出相应的数据转换。
2. Stream 就如同⼀个迭代器(Iterator),单向,不可往复,数据只能遍历⼀次,遍历过⼀次后即⽤尽了,就好⽐流⽔从⾯前流过,⼀
去不复返。
3. Stream 的数据源本⾝可以是⽆限的。
Stream()类的⽅法
1. filter (过滤器)
这个过滤器的⽅法就是对流中的数据⼀个⼀个的进⾏筛选,看看它是不是符合规则,如果不符合就拦截住,也就是舍弃,如果符合要求,则让他通过,进⾏下⼀步的操作,说⽩了就像⼀个滤⽹⼀样,我们可以设置过滤的规则,然后它对数据流进⾏筛选;
⽐如上⾯的例⼦来说我们就可以⽤这样的⽅法;
List<Integer> list = Arrays.asList(1,2,3,4,5,6);
List<Integer> stream = list.stream().filter( i ->
i%2==0).List());
System.out.print(stream);
我们可以看到filter的参数就是⼀个Predicae<>断⾔;也就是说我们可以给它⾥⾯传⼀个lambda表达式,就是过滤的规则; 同时它返回的⼜是⼀个Stream流对象,这时我们⼜可以⽤它的collect(收集器),对过滤下来的数据收集起来,把他存⼊⼀个List集合;然后这时候我们输出得到的这个集合,就是我们收集的数据;
2. map (映射)
映射的, lambda把原有的元素转换为另⼀个元素, 不会改变个数;
上⾯的filter过滤器就是给把我们的数据按我们的规则筛选出来,那map()⽅法就是将我们的元素按照规则映射成另外的元素;⽐如我们要得到上⾯的list集合中的所有元素的2倍的集合,这时候我们就需要⽤到map()⽅法;
List<Integer> list4 = Arrays.asList(1,2,3,4,5,6);
List<Integer> collect = list4.stream().map(i ->
i *2).List());
System.out.println(collect);
这只是简单的映射,我们⼜得到了需要的数据,同时原集合仍然存在;我们再看看map()⽅法的参数;
这⾥我们需要⼀个Function()参数,这个模式的⽅法lambda表达式的写法就是⼀个参数,返回⼀个结果;
map(i -> i * 2)
这句映射就很直观的帮我们解释了Function接⼝的特性;
3. == flatMap(扁平化映射)==
这个类就好⽐是流的类型转换;
⽐如我们现在定义了⼀个list集合,它的元素是字符串数组;
List<String[]> list =new ArrayList<>();
list.add(new String[]{"张三","李四"});
list.add(new String[]{"王五","张三"});
list.add(new String[]{"钱七","周⼋"});
如果我们想将它⾥⾯的每个字符串提取出来,组成⼀个新的集合,按照原来的⽅法我们就需要两重遍历,先遍历集合,后遍历数组,得到每⼀个字符串元素,再新建⼀个集合,将它们存进去;
List<String> list2 =new ArrayList<>();
for(String[] strings : list){
for(String string : strings){
list2.add(string);
}
}
System.out.println(list2);
可如果⽤flatmap⽅法做扁平化映射时就特别简单,我们⼀句话就可以得到这个集合;
List<String> list3 = list.stream().flatMap( s ->
Arrays.stream(s)).List());
flatmap的参数同样是⼀个Function,只是这次我们传⼊的参数是list集合的元素String[]数组,把它映射成⼀个数组流Arrays.stream,然后collect收集起来;这个⽅法就很⽅便;
它就可以⽤在我们平时⼤规模数据转换的时候,⽤流的⽅式,得到需要的格式;
4. forEach
遍历流,接收⼀个Consumer
list3.stream().forEach((a)->{
System.out.println(a);
});
5. map的流遍历
接收⼀个BiConsumer
java streamMap<String, String> map =new HashMap<>();
map.put("a","张");
map.put("b","李");
map.forEach((key, value)->{
System.out.println("key:"+key +" value:"+ value);
});
重要模式
上⾯说了很多种的模式,再这⾥我们统⼀进⾏⼀下说明;
1. Predicate 断⾔接⼝
对应的lambda ⼀个参数,返回结果是boolean
(a) -> { return true|false; }
2. BiPredicate 双参数断⾔
对应的lambda 两个参数,返回结果是boolean
(a, b) -> { return true|false; }
3. Function 函数接⼝
对应的lambda ⼀个参数,⼀个返回结果,参数和返回结果的类型可以不⼀样
4. BiFunction 双参数函数接⼝
两个参数,⼀个结果
(a, b) -> { 根据ab返回⼀个结果}
5. Consumer 消费接⼝
⼀个参数 没有结果
(a) -> { 不需要return }
6. BiConsumer 双参数消费接⼝
两个参数,没有结果
(a,b) -> { 不需要return }
7. Supplier ⽣产者接⼝
没有参数,返回⼀个结果
() -> {return 结果}
有了这些模式知识的帮忙我们就可以更好的理解Stream()中⽅法的参数需求了;
7. 其它常见api
求个数count()
System.out.println(list3.stream().count());
去除重复distinct()
System.out.println(list3.stream().distinct().collect(toList()));
获取最⼤最⼩值(参数需要⼀个⽐较器)
// 返回的是Optional 类型,怕集合为空时,没有合法的最⼤值
List<String> list4 = Arrays.asList("zhang","li","zhao","wang"); System.out.println(list4.stream().max((a, b)-> apareTo(b))); System.out.println(list4.stream().min((a, b)-> apareTo(b)));
如果是数字流,除了最⼤最⼩值外,还有平均值,和
System.out.println(IntStream.of(1,2,3,4,5,6,7,8,9,10).max()); System.out.println(IntStream.of(1,2,3,4,5,6,7,8,9,10).min()); System.out.println(IntStream.of(1,2,3,4,5,6,7,8,9,10).average()); System.out.println(IntStream.of(1,2,3,4,5,6,7,8,9,10).sum());
有了上⾯的知识我们来做⼀个⽐较复杂的需求:
我们定义了⼀个学⽣类,它的属性包括名字,性别,所在城市;
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论