Stream是一组用来处理数组、集合的API
Java8之所以竭力引入函数式编程,原因有:
Stream特性:
Stream运行机制:
Stream分为源source,中间操作,终止操作
stream的源可以是一个数组、一个集合、一个生成器方法,一个I/O通道等等
一个流可以有零个或者多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用.一个流只会有一个终止操作
Stream只有遇到终止操作,它的源才开始执行遍历操作
Stream的创建
接下来我们通过数组的方式来生成stream
public class StreamDemo {
public void gre(){//通过数组来生成Stream
String[] strs = {"a","b","c","d"};
Stream<String> st1 = Stream.of(strs);
st1.forEach(System.out::println);
}
public static void main(String[] args) {
new StreamDemo().gre();
}
}
接下来我们通过列表的方式来生成stream
static void greList(){
List<String> list = Arrays.asList("a","b","c","d");
Stream<String> st1 = list.stream();
st1.forEach(System.out::println);
}
public static void main(String[] args) {
new StreamDemo().gre();
}
接下来通过generate方式创建
static void greGenerate(){
Stream<Integer> stream = Stream.generate(()->1);
stream.limit(10).forEach(System.out::println);
}
但generate创建的元素值都是相同的,若想是有规律的递增,只能iterate创建
接下来通过iterate方式创建
static void greIterate(){
Stream<Integer> integerStream = Stream.iterate(1,x->x+1);
integerStream.limit(10).forEach(System.out::println);
}
或者通过别的API进行创建,这里只是举个例子
static void greOther(){
String str = "adafcvxcv";
IntStream stream = str.chars();
stream.forEach(System.out::println);
}
Stream常用API
中间操作
过滤 filter
去重 distinct
排序 sorted
截取 limit、skip
转换 map/flatMap
其他 peek
中间操作:如果调用方法之后返回的结果是stream对象就意味着这是个中间操作
编写个小程序,从一个集合中取出所有的偶数
public static void main(String[] args) {
Arrays.asList(1,2,3,4,5).stream().filter(x->x%2==0).forEach(System.out::println);
}
解读:生成集合后,将集合转成stream,然后使用filter,设置过滤条件为模2为0 ,最后遍历取出合适的数值进行打印
接下来写个小程序统计集合中偶数的个数
long count = Arrays.asList(1, 2, 3, 4, 5, 6, 7).stream().filter(x -> x % 2 == 0).count();
System.out.println(count);
接下来写个小程序统计集合中的偶数的和
注意这里我们就不能使用stream来求和了,只能将stream转成IntStream再进行求和操作
下面的mapToInt起到的就是这个作用
int sum = Arrays.asList(1, 2, 3, 4, 5, 6, 7).stream().filter(x -> x % 2 == 0).mapToInt(x -> x).sum();
System.out.println(sum);
编写个小程序,求集合中的最大值和最小值
List<Integer> integers = Arrays.asList(5, 3, 1, 5, 9, 10, 8, 6);
Optional<Integer> max1 = integers.stream().max((a, b) -> a - b);
Optional<Integer> min = integers.stream().min((a, b) -> a - b);
System.out.println(max1.get()+"-----"+min.get());
终止操作
循环 forEach
计算 min、max、count 、 average
匹配 anyMatch 、 allMatch 、 noneMatch 、 findFirst 、findAny
汇聚 reduce
收集器 toArray collect
注意:终止操作后,流就已经处于关闭状态了,所以后续操作就不能再调用当前流了
findFirst和findAny作为流的终止操作.两者对流的遍历都会有终止操作.从字面意思我们可以理解到,findFirst只会返回匹配到的第一个合适的值,findAny会随机返回匹配到的合适的值,但是这里需要注意到一点,在小数据量、串行的情况下,findAny也会只返回第一个结果,只有在并行的情况下才会随机返回
List<String> strs = Arrays.asList("jj","dd","jk","js","dg","di","je","jq");
List<String> strs2 = Arrays.asList("jj","dd","jk","js","dg","di","je","jq");
Optional<String> e = strs.parallelStream().filter(x -> x.startsWith("d")).findFirst();
Optional<String> d = strs2.parallelStream().filter(x -> x.startsWith("j")).findAny();
System.out.println(e.get()+"-------------"+d.get());
使用sorted进行排序
List<String> strings = Arrays.asList("c++","air","js","python","c#","win","scala","flash","java");
Stream<String> sorted1 = strings.stream().sorted();//不添加排序条件的话,就是自然排序,根据首字母进行排序
Stream<String> sorted2 = strings.stream().sorted((a,b)->a.length()-b.length());//这里添加的排序条件是依照字符串长度来排序
sorted1.forEach(System.out::println);
将排序后的流返回成一个新的集合
List<String> strings = Arrays.asList("c++","air","js","python","c#","win","scala","flash","java");
List<String> collect = strings.stream().sorted((a, b) -> a.length() - b.length()).collect(Collectors.toList());
collect.forEach(System.out::println);
对集合进行去重并排序
Arrays.asList(1,1,5,6,7,8,5,3,3,2,1).stream().distinct().sorted().forEach(System.out::println);
这里的distinct()具有去重的作用,sorted具有排序的作用
除了distinct方法外,我们还可以使用什么方式来进行去重呢?——Set集合具有无序、唯一的特点,我们可以将集合转成Set,也能达到去重的效果
Arrays.asList(1,1,5,6,7,8,5,3,3,2,1).stream().collect(Collectors.toSet()).forEach(System.out::println);
打印20-30的集合数据
这里有两种方式
方法一:
Stream.iterate(1,x->x+1).limit(50).skip(20).limit(10).forEach(System.out::println);
方法二:
Stream.iterate(20,x->x+1).limit(10).forEach(System.out::println);
现有字符串 String str = " 1,3,5,11,2,4" 如何求字符串中所有数字之和呢?
先来看下我们正常情况下java语言是咋写的
String str = " 1,3,5,11,2,4";
String[] spli = str.split(",");
int sum = 0;
for (String ss:spli){
int a = Integer.valueOf(ss.trim());
sum = sum+a;
}
System.out.println(sum);
如果此时通过我们的StreamAPI是一种什么养的效果呢?
String str = " 1,3,5,11,2,4";
System.out.println(Stream.of(str.split(",")).mapToInt(x->Integer.valueOf(x.trim())).sum());
由于字符串中带了空格,若是不带空格的话,我们还可以写得更简便写
String str = "1,3,5,11,2,4";
System.out.println(Stream.of(str.split(",")).mapToInt(Integer::valueOf).sum());
也可以这样写
System.out.println(Stream.of(str.split(",")).map(Integer::valueOf).mapToInt(x -> x).sum());
我们也可以在Stream中调用自己创建的类的方法引用
Stream.of(str.split(",")).map(x->new TestFunction2()).forEach(System.out::println);
Stream.of(str.split(",")).map(TestFunction2::new).forEach(System.out::println);
Stream.of(str.split(",")).map(TestFunction::stringStr).forEach(System.out::println);