Java——StreamAPI

Stream

Stream是一组用来处理数组、集合的API
Java8之所以竭力引入函数式编程,原因有:

  1. 代码简洁:函数式编程写出的代码简洁意图明确,使用Stream接口让你从此告别for循环
  2. 多核友好:Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一些parallel()方法
    所以,函数式编程极大可能是未来主流的编程方式,我们最好能养成函数式编程的思维方式

Stream特性:

  1. 不是数据结构,没有内部存储
  2. 不支持索引访问
  3. 延迟计算
  4. 支持并行
  5. 很容易生成数组集合(List、Set)
  6. 支持过滤,查找、转换,汇总,聚合等操作

Stream运行机制:
Stream分为源source,中间操作,终止操作
stream的源可以是一个数组、一个集合、一个生成器方法,一个I/O通道等等
一个流可以有零个或者多个中间操作,每一个中间操作都会返回一个新的流,供下一个操作使用.一个流只会有一个终止操作
Stream只有遇到终止操作,它的源才开始执行遍历操作

Stream的创建

  1. 通过数组
  2. 通过集合
  3. 通过Stream.generate方法来创建
  4. 通过Stream.iterate方法来创建
  5. 其他API创建

接下来我们通过数组的方式来生成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作为流的终止操作.两者对流的遍历都会有终止操作.从字面意思我们可以理解到,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);

你可能感兴趣的:(java,stream)