set.stream使用 java_Java进阶 - Stream流、方法引用

1.Stream流

关注的是做什么,而不是怎么做

步骤:(1)拼接流式模型:建立生产线

用Stream流进行遍历打印

public classForStream {public static voidmain(String[] args) {

List list = new ArrayList<>();

list.add("林子东");

list.add("蔡晓武");

list.add("夏琨");

list.add("林子成");

list.add("林峰");//对集合进行过滤,要以林开头,且长度为3,最后输出打印//首先将集合转换为Stream流

list.stream()//filter参数是predicate接口,可以用lanmda表达式进行判断

.filter(name -> name.startsWith("林"))

.filter(name-> name.length()==3)//forEach参数是consumer接口,可以消费打印

.forEach(name->System.out.println(name));

}

}

模型:

e709c4f380106e0e380c31e9951ef25a.png

filter 、 map 、 skip 都是在对函数模型进行操作,集合元素并没有真正被处理。只有当终结方法 count执行的时候,整个模型才会按照指定策略执行操作。而这得益于Lambda的延迟执行特性。

备注:“Stream流”其实是一个集合元素的函数模型,它并不是集合,也不是数据结构,其本身并不存储任何元素(或其地址值)。

Stream(流)是一个来自数据源的元素队列

元素是特定类型(指定泛型)的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。

数据源:流的来源。 可以是集合,数组 等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluentstyle)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

内部迭代: 以前对集合遍历都是通过Iterator或者增强for的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式,流可以直接调用遍历方法。

当使用一个流的时候,通常包括三个基本步骤:获取一个数据源(source)→ 数据转换→执行操作获取想要的结果,每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道。

2.获取流

获取一个流非常简单,有以下几种常用的方式:

所有的 Collection 集合(map集合不行)都可以通过 stream 默认方法获取流;

Stream 接口的静态方法 of 可以获取数组对应的流。

public classGetStream {public static voidmain(String[] args) {//list集合

List list = new ArrayList<>();

Stream stream1 =list.stream();//set集合

Set set = new HashSet<>();

Stream stream2 =set.stream();//map集合间接调用

Map map = new HashMap<>();//获取键,存储到一个set集合中

Set keySet =map.keySet();

Stream stream3 =keySet.stream();//获取值,存储到Collection集合中

Collection values =map.values();

Stream stream4 =values.stream();//获取键值对(键与值的映射关系)

Set> entries =map.entrySet();

Stream> stream5 =entries.stream();//把数组转换为stream流

Stream integerStream = Stream.of(1, 2, 3, 4, 5);//可变参数可以传递数组

Integer[] arr = {1,2,3,4,5};

Stream stream6 =Stream.of(arr);

}

}

3.Stream流常用方法

(1)forEach,参数为Consumer接口,用于遍历,属于终结型方法

(2)filter,参数为Predicate接口,用于过滤,属于延迟方法,返回一个新的流对象

public classNormalMethod {public static voidmain(String[] args) {

Stream stream = Stream.of("张三丰", "张志杰", "赵敏");//进行过滤

Stream nameList = stream.filter(name -> name.startsWith("张"));//遍历输出

nameList.forEach(name->System.out.println(name));

}

}

(3)map,参数为Function接口,用于映射,属于延迟方法,返回一个新的流对象

public classNormalMethod {public static voidmain(String[] args) {

Stream stream = Stream.of("1", "2", "3");//进行转换

Stream integerStream = stream.map(num ->Integer.parseInt(num));//遍历输出

integerStream.forEach(name->System.out.println(name));

}

}

(4)count,终结方法,用于统计元素个数,返回一个long类型的数

(5)limit,延迟方法,用于截取前几个元素,输入几就截取几个,返回一个新的流对象

(6)skip,跳过前几个,保留后几个,如果有三个元素,输入4,则返回空的流

(7)Stream的静态方法concat,用于合并两个流,得到一个新的流

4.方法引用

方法引用符

双冒号 :: 为引用运算符,而它所在的表达式被称为方法引用。如果Lambda要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为Lambda的替代者。

语义分析

例如上例中, System.out 对象中有一个重载的 println(String) 方法恰好就是我们所需要的。那么对于printString 方法的函数式接口参数,对比下面两种写法,完全等效:

Lambda表达式写法: s -> System.out.println(s);

方法引用写法: System.out::println

第一种语义是指:拿到参数之后经Lambda之手,继而传递给 System.out.println 方法去处理。

第二种等效写法的语义是指:直接让 System.out 中的 println 方法来取代Lambda。两种写法的执行效果完全一样,而第二种方法引用的写法复用了已有方案,更加简洁。

注:Lambda 中 传递的参数 一定是方法引用中 的那个方法可以接收的类型,否则会抛出异常

接口:

@FunctionalInterfacepublic interfaceprintable {voidprint(String s);

}

打印类:public classUpperMethod {public voidtoUp(String s){

System.out.println(s.toUpperCase());

}

}

主方法:public classDemoPrintable {public static voidmain(String[] args) {//先创建对象,通过对象对已存在的方法进行方法引用

UpperMethod obj = newUpperMethod();

method(obj::toUp,"ddd");

}public static voidmethod(printable p, String s) {

p.print(s);

}

}

(2)通过类名称引用静态方法

由于在 java.lang.Math 类中已经存在了静态方法 abs ,所以我们可以直接用类名进行方法引用

(3)通过super引用父类的成员方法 要求:有子父类 且父类方法存在

method(super::greet)

(4)也可以通过this来引用本类的方法 this::method

(5)类的构造器引用

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

接口:public interfacePersonBuilder {//给个名字创建一个Person对象

Person build(String name);

}

Person类:public classPerson {privateString name;publicPerson() {

}publicPerson(String name) {this.name =name;

}publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}

}

测试类:public classDemoBuildPerson {public static voidmain(String[] args) {//类的构造器引用

/*printName("迪丽热巴",(String name)->{

return new Person(name);

});*/

//优化

printName("迪丽热巴",Person::new);

}public static voidprintName(String name,PersonBuilder pb){

Person p1=pb.build(name);

System.out.println(p1.getName());

}

}

View Code

(6)数组的构造器引用

method(10,int[]::new);

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值