Java流式编程简介

JAVA 流式编程

简介

流式编程是java8的新特性之一,将数据像水流一样进行处理,能让一些代码更加简洁明了

快速开始

import java.util.stream.IntStream;

public class Main {

    public static void main(String[] args) {
        IntStream.range(1,10)                   // 获取一个整型数字流
                .limit(5)                       // 限制5个
                .filter(x -> x%2 == 1)          // 筛选掉偶数
                .forEach(System.out::println);  // 输出
    }
}

上述的代码中通过IntStream获取一个整型的输入流,然后经过limit筛选剩下前5个元素,然后通过filter进行筛选,最后输出

流的获取

流的获取比较简单,可以通过数组、列表进行转换,或者可以使用java已经定义好的基本类型的流来生成:

import java.util.*;
import java.util.function.DoubleSupplier;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Main {

    public static void main(String[] args) {
        IntStream.range(1, 10)                   // 获取一个整型数字流
                .limit(5)                       // 限制5个
                .filter(x -> x % 2 == 1)          // 筛选掉偶数
                .forEach(System.out::println);  // 输出
        getStream();
    }

    public static void getStream() {

        //double流通过随机数的获取
        DoubleStream doubleStream2 = new Random()
                .doubles(10)
                .distinct();
        
        //int流获取
        IntStream intStream1 = IntStream.range(1,10);

        //double流获取,还有其他基本类型的流,如long,char等等,此处不一一列举
        DoubleStream doubleStream = DoubleStream.generate(new DoubleSupplier() {
            @Override
            public double getAsDouble() {
                return Math.random();
            }
        });

        //将数组转换成流
        double[] arr = new double[]{1.1, 1.2, 4.5, 2.3, 1.0, 9.0};
        DoubleStream doubleStream1 = Arrays.stream(arr);

        //通过数组生产字符串流
        String[] strArr = new String[]{"a" , "b" , "d" , "a"};
        Stream<String> stringStream =Arrays.stream(strArr);

        //对象流
        Node node_1 = new Node().setId(1).setName("node_1").setValue(100);
        Node node_2 = new Node().setId(2).setName("node_2").setValue(50);
        Node node_3 = new Node().setId(3).setName("node_1").setValue(90);

        List<Node> nodeList = new ArrayList<>(){
            {
                add(node_1);
                add(node_2);
                add(node_3);
            }
        };
        Stream<Node> nodeStream = nodeList.stream();
    }
}

class Node{
    int id;
    String name;
    int value;
    public int getId() { return id;}
    public Node setId(int id) {
        this.id = id;
        return this;
    }

    public String  getName() {return name;}
    public Node setName(String name) {
        this.name = name;
        return this;
    }

    public int getValue() {return value;}
    public Node setValue(int value) {
        this.value = value;
        return this;
    }
}

流的处理

常见的流的处理有以下这些

操作参数说明
map一个映射函数,如 map(x->x+1)将流各个元素进行逐一映射
sortedComparator (可选)排序处理,基本类型默认升序
peek具体操作,比如peek(System.out::println)对每个元素执行相应的操作,一般不改变元素的值,多用于调试
filter筛选函数,比如filter(x->x%2==0)通过定义的函数,对元素进行筛选
limitint限制流输出的数量
foreach具体操作,比如foreach(System.out::println)对每个元素执行相应的操作
import java.util.*;
import java.util.function.DoubleSupplier;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class Main {

    public static void main(String[] args) {
        IntStream.range(1, 10)                   // 获取一个整型数字流
                .limit(5)                       // 限制5个
                .filter(x -> x % 2 == 1)          // 筛选掉偶数
                .forEach(System.out::println);  // 输出
//        getStream();
        new Main().process();
    }



    public void process(){
        Node node_1 = new Node().setId(1).setName("node_1").setValue(100);
        Node node_2 = new Node().setId(2).setName("node_2").setValue(50);
        Node node_3 = new Node().setId(3).setName("node_1").setValue(90);
        List<Node> nodeList = new ArrayList<>(){
            {
                add(node_1);
                add(node_2);
                add(node_3);
            }
        };
        Stream<Node> nodeStream = nodeList.stream();
        List<Node> list = nodeStream.sorted((x1,x2)->x1.value-x2.value)
                .peek(x-> System.out.print(x.id+" "))
                .peek(x-> System.out.print(x.value+" "))
                .map(x->new Node().setId(x.id).setName(x.name).setValue(x.value*10))
                .peek(x-> System.out.print(x.value+" "))
                .filter(x->x.id!=2)
                .limit(2).collect(Collectors.toList());

        System.out.println();
        System.out.println(list.toString());
    }


}

class Node{

    int id;
    String name;
    int value;

    public int getId() {
        return id;
    }

    public Node setId(int id) {
        this.id = id;
        return this;
    }

    public String  getName() {
        return name;
    }

    public Node setName(String name) {
        this.name = name;
        return this;
    }

    public int getValue() {
        return value;
    }

    public Node setValue(int value) {
        this.value = value;
        return this;
    }

    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", value=" + value +
                '}';
    }
}

代码中通过collect将stream转换为一个列表返回,类似的还有toArray,建议亲自试一下

上面的程序中有一个值得注意的点,就是当filter筛掉id=2 和筛掉id=1这两种情况的时候输出的数量是不同的!

# filter(x->x.id==2)
2 50 500 3 90 900 1 100 1000 
[Node{id=3, name='node_1', value=900}, Node{id=1, name='node_1', value=1000}]

# filter(x->x.id==2)
2 50 500 3 90 900 
[Node{id=2, name='node_2', value=500}, Node{id=3, name='node_1', value=900}]

简单思考一下就会发现为什么:筛选id2的时候,filter还没有应用到stream上面,所以peek会输出id=2的数据,但是当id1的时候因为id为1的数据是最后输出的,filter已经应用了所以会直接在开头就被筛选掉.

reduce

reduce操作的特别之处在于提供了一个初始的值进行操作,字符串的拼接,sum,min,max,average都是特殊的reduce,比如字符串的拼接中,使用了"Head:"作为初始值

public void reduce(){

    int max = IntStream.range(1,10).reduce(0 , Integer::max);

    String[] strings = new String[]{"I ","love ","java ","and ","go"};
    String sentance = Arrays.stream(strings).reduce("Head:",String::concat);

    System.out.println("max:"+max);
    System.out.println("sentance:"+sentance);


}
max:9
sentance:Head:I love java and go

parallel

parallel是将数据并行处理,在多核心CPU中速度相对较快,但是并行的过程中数据是无序的,但是如果最终结果会回复有序的状态

public void parallel(){

        int a[] = IntStream.range(1,15).parallel().toArray();

        String[]strings = new String[]{"a","b","a","ad"};

        List<String> list = Arrays.stream(strings).parallel().sorted().collect(Collectors.toList());
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i)+" ");
        }
        System.out.println();

        Arrays.stream(a).parallel().sorted().forEach(x-> System.out.print(x+" "));
        System.out.println();
        Arrays.stream(a).forEach(x-> System.out.print(x+" "));
        System.out.println();
        list.stream().sorted().forEach(x-> System.out.print(x+" "));
        System.out.println();
        list.stream().parallel().sorted().forEach(x-> System.out.print(x+" "));

    }
a a ad b 
13 12 14 11 7 4 10 3 6 5 9 8 1 2 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 
a a ad b 
a ad b a 

参考文章

文章一:https://blog.csdn.net/weixin_41231928/article/details/105930941
文章二:https://www.jianshu.com/p/40b36b2ccf97

更多内容

请关注: https://panrh.com

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值