一 Stram编程
主要是 回忆 jdk1.8提供的stream编程中一些方法,还有scala中类似流的操作,以及kafka中无状态操作算子的区分,老是区分不了,今天写一篇文章,加深自己的印象,首先介绍jdk1.8新特性stream
所谓jdk1.8出现的Stream就是对一些集合功能的增强,他可以对集合中的元素做到细粒度的控制扫描,将其转换为类似一条流水线,并对其进行处理,stream的出现简化了java开发,并且提高了并发效率吗,一般流分为中间操作和终端操作
1.1 jdk1.8 stream中间操作
limit
: 截短流 参数是一个long 返回值也是流
import java.util.Arrays;
import java.util.stream.Collectors;
public class StreamDemo01 {
public static void main(String[] args) {
Arrays.asList("GX", "XM", "ZS", "LS", "WL")
//将集合转换为流
.stream()
//保留前2位元素
.limit(2)
//调用collect 将流转换为一个集合 类似于终端操作 Collectors.toList()
.collect(Collectors.toList())
// 遍历打印输出
.forEach(System.out::println);
}
}
filter
:将流中元素以某种规则过滤 参数是元素 返回值是一个boolean
distinct: 过滤重复元素
public class StreamDemo01 {
public static void main(String[] args) {
Arrays.asList("GX", "XM", "ZS", "LS", "WL","ZS")
//将集合转换为流
.stream()
//以某种规则进行过滤
.filter(v->v.startsWith("Z"))
//过滤重复元素
.distinct()
//调用collect 将流转换为一个集合 类似于终端操作 Collectors.toList()
.collect(Collectors.toList())
// 遍历打印输出
.forEach(System.out::println);
}
}
map
: 将流中的元素转换为另外一种元素 参数是一个function
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class StreamDemo01 {
public static void main(String[] args) {
List<Student> list = new ArrayList<>();
list.add(new Student("GX", "123456"));
list.add(new Student("ZS", "123456"));
list.add(new Student("LS", "123456"));
list.add(new Student("XM", "123456"));
list.stream()
// 将流中的元素 一种泛型转换为另外一种泛型 Student-> String
.map(Student::getName)
.collect(Collectors.toList())
.forEach(System.out::println);
}
}
class Student {
private String name;
private String password;
public Student() {
}
public Student(String name, String password) {
this.name = name;
this.password = password;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
flatMap
扁平化 参数描述 T->Stream<R> 将T 变为一个R 并且是以R为泛型的Stream 最后返回
public static void main(String[] args) {
Arrays.asList("Hello word", "Hello Kafka", "Hello Hadoop", "Hello SpringBoot", "Hello Spark","Hello Zookeeper")
//将集合转换为流
.stream()
// 将字符串以某种规则转换为一个数组并且返回 返回值是一个流
.flatMap(v->{
String[] split = v.split(" ");
return Arrays.stream(split);
})
//过滤重复元素
.distinct()
//调用collect 将流转换为一个集合 类似于终端操作 Collectors.toList()
.collect(Collectors.toList())
// 遍历打印输出
.forEach(System.out::println);
}
1.2 scala中的Stream编程
scala中的匿名函数在最后奉献
java 中的Stream 编程来于scala ,scala是一种多范式的编程语言,其中内置了23个函数对象,scala是一门纯面向对象的语言,可以运行在jvm虚拟机中,也可以运行在js中 scala中Stream 类似于java
map
java中的map将一个元素变为另外一种元素,内部可以进行细粒度的控制,当然scala中也是
package demo02
object StreamDemo02 {
def main(args:(Array[String])): Unit ={
val arr = Array(1,2,3,4)
arr.map(k=>k*2).foreach(k=>println(k))
}
}
scala中的wordCount 实现单词技术功能
package demo02
object StreamDemo02 {
def main(args:(Array[String])): Unit ={
val arr = Array("Hello word","Hello spring","Hello SpringCloud","Hello SpringBoot","Hello SpringMvc")
//展开 将每个字符串按空格进行切分
arr.flatMap(k=>k.split(" "))
//然后映射成一个map集合
.map(k=>(k,1))
// 根据键进行分组操作 参数是一个function对象
.groupBy((k:(String,Int))=>k._1)
// 将分组后再次映射为一个map
.map(k=>(k._1,k._2.length))
.foreach(k=>println(k))
}
}
1.3kafka中无状态操作算子
kafka作为流数据处理平台 其中最重要的`Kafka Straming 是一个用于构建应用程序和微服务的客户端库,其中的输入和输出数据存储在Kafka集群中。它结合了在客户端编写和部署标准Java和Scala应用程序的简单性,以及Kafka服务器端集群技术的优点
简单回顾一下 kafka Streaming
kafkaStraming 消费者从topic拉取数据到缓冲区,然后topology 会从缓冲区中拉去属于自己的数据,每一个topology由多个processor 构成 形成有向无环图,其中有state store 用来存放计算的中间结果,最后通过计算的结果将数据通过Stream thread 中的producer写出到topic中
无状态操作算子 指的是没有数据产生 状态指的是数据 一般是 Kstream -> Kstream
无状态的操作算子, 指进行数据转换操作时不会涉及到状态的管理
-
Branch
KStream ----> KStream[]
KStream<String, String>[] kStreams = stream.branch( (k, v) -> v.startsWith("A"), // stream: A开头 (k, v) -> true // 其它数据 ); kStreams[0].foreach((k,v) -> System.out.println(k + "\t"+v));
-
Filter
KStream —> KStream
保留符合Boolean条件(true)的数据
stream .filter((k,v) -> v.startsWith("H")) .foreach((k,v) -> System.out.println(k+"\t"+v));
-
filterNot
KStream → KStream
KTable → KTable
保留不符合Boolean条件的数据
stream .filterNot((k,v) -> v.startsWith("H")) .foreach((k,v) -> System.out.println(k+"\t"+v));
-
FlatMap
KStream → KStream
将一个Record展开为0-n个Record
stream .flatMap((k,v) -> Arrays.asList( new KeyValue<String,String>(k,v.toUpperCase()+"!"), new KeyValue<String,String>(k,v.toLowerCase()+"?"))) .foreach((k,v) -> System.out.println(k +"\t" + v));
-
flatMapValues
KStream → KStream
将一个Record的value展开为1到N个新的value(key不变)
stream // null Hello World //-------------------- // null Hello // null World .flatMapValues((v) -> Arrays.asList(v.split(" "))) .foreach((k, v) -> System.out.println(k + "\t" + v));
-
Foreach
KStream → void (终止操作)
对KStream中的数据进行迭代遍历,无返回值
stream // null Hello World //-------------------- // null Hello // null World .flatMapValues((v) -> Arrays.asList(v.split(" "))) .foreach((k, v) -> System.out.println(k + "\t" + v));
-
GroupBy
KStream → KGroupedStream
根据指定的信息 进行分区操作,注意分组时会进行Shuffle(洗牌)
//============================groupBy=================================== stream // null Hello World //-------------------- // null Hello // null World .flatMapValues((v) -> Arrays.asList(v.split(" "))) .groupBy((k,v) -> v) .count() .toStream() .foreach((k,v) -> System.out.println(k+"\t"+v)); //======================================================================
-
GroupByKey
KStream → KGroupedStream
根据已存在的key值进行分区操作(洗牌)
stream // null Hello World //-------------------- // null Hello // null World .flatMapValues((v) -> Arrays.asList(v.split(" "))) .map((k,v) -> new KeyValue<String,Long>(v,1L)) .groupByKey(Grouped.with(Serdes.String(),Serdes.Long())) .count() .toStream() .foreach((k,v) -> System.out.println(k+"\t"+v));
-
Map
KStream → KStream
将一个流中的一条数据映射为另外一条数据
-
mapValues
类似于map操作,不同key不可变,V可变
stream // null Hello World //-------------------- // null Hello // null World .flatMapValues((v) -> Arrays.asList(v.split(" "))) .map((k,v) -> new KeyValue<>(v,1L)) .mapValues(v -> v = v+1) .foreach((k,v) -> System.out.println(k+"\t"+v));
-
Merge
KStream → KStream
将两个流合并为一个大流
KStream<String, String>[] streams = stream .branch( (k, v) -> v.startsWith("A"), (k, v) -> v.startsWith("B"), (k, v) -> true ); streams[0].merge(streams[2]) .foreach((k,v) -> System.out.println(k+"\t"+v));
-
Peek
KStream → KStream
探针(调试程序): 不会改变数据流内容
stream.peek((k,v) -> System.out.println(k+"\t"+v));
-
Print
等价于
foreach((key, value) -> System.out.println(key + ", " + value))
stream.print(Printed.toSysOut());
-
SelectKey
KStream → KStream
给流中的数据,分配新的k值(k变,v不变)
stream.selectKey((k,v) -> "Hello:").print(Printed.toSysOut());
-
Table to Stream
KTable → KStream
table.toStream();
补充!关于 scala 中高阶函数