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) | 将流各个元素进行逐一映射 |
sorted | Comparator (可选) | 排序处理,基本类型默认升序 |
peek | 具体操作,比如peek(System.out::println) | 对每个元素执行相应的操作,一般不改变元素的值,多用于调试 |
filter | 筛选函数,比如filter(x->x%2==0) | 通过定义的函数,对元素进行筛选 |
limit | int | 限制流输出的数量 |
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