在上一篇讲到java8中什么是Stream流和Stream流有什么用:java8——学习Stream流(一):创建Stream流,这里我们会讲到创建流之后,我们可以对其创建的流进行的中间操作,多个中间操作可以连接起来形成一个流水线,除非流水线上触发了终端操作,否则中间操作并不会执行任何的处理!而是在终端操作时一次性全部处理,我们称之为“惰性求值”。
中间操作:1.筛选和切片
- 我们先创建一个实体类``:Enployee 类
public class Enployee {
private Integer id;
private String name;
private Integer age;
private Integer salary;//薪水
public Enployee() {
}
public Enployee(Integer id) {
this.id=id;
}
public Enployee(Integer id, String name, Integer age, Integer salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getSalary() {
return salary;
}
public void setSalary(Integer salary) {
this.salary = salary;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((salary == null) ? 0 : salary.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Enployee other = (Enployee) obj;
if (age == null) {
if (other.age != null)
return false;
} else if (!age.equals(other.age))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (salary == null) {
if (other.salary != null)
return false;
} else if (!salary.equals(other.salary))
return false;
return true;
}
@Override
public String toString() {
return "Enployee [id=" + id + ", name=" + name + ", age=" + age + ", salary=" + salary + "]";
}
}
2让我们尝试使用一下filter
@Test
public void test(){
Stream<Enployee> stream = list.stream();
stream.filter((x)->{
System.out.println("中间操作");
return x.getSalary()>3000;
})//中间操作,需要一个断言性接口
//当我们没有进行终端操作的时候,会发现中间操作的打印功能并没有执行,说明中间操作只有在终端操作被执行的时候才会执行中间操作
.forEach(System.out::println);
}
.
3. 使用limit(截断流:可以使遍历出来的元素在新的集合或者数组中不超过指定的元素个数,并且取完指定的个数后,就不会再进行遍历了)
@Test
public void test2(){
Stream<Enployee> stream2 = list.stream();
stream2.filter((x)->x.getSalary()>2000)
.limit(2)//截断流:从内部迭代器中取出的元素不超过2个,优先取先遍历出来的元素
.forEach(System.out::println);
}
- 使用skip(n)——跳过遍历出来的执行的前n个元素,然后再进行取值,并放入新的集合或者数组中。
若遍历的集合或者数组中的元素不足n个,就执行返回一个空的流
@Test
public void test3(){
Stream<Enployee> stream3 = list.stream();
stream3.filter((x)->x.getSalary()>2000)
.skip(2)
.forEach(System.out::println);
}
- 使用distinct()——去掉遍历出来的重复元素,通过流所生成的元素的hascode()与equals()去重复元素
所以我们需要重写hascode和equals方法
@Test
public void test4(){
Stream<Enployee> stream4 = list.stream();
stream4.filter((x)->x.getSalary()>2000)
.skip(2)
.distinct()//去掉遍历出来的重复元素
.forEach(System.out::println);
}
中间操作:2.映射
- 利用map映射把一个函数映射到每个元素上
//使用map映射中间操作
List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
@Test
public void test1(){
//lambda表达式作用到集合中每一个元素中
Stream<String> stream = list.stream();
stream.map((x)->x.toUpperCase())//调用toUpperCase方法,把每一个元素从小写变成大写
.forEach(System.out::println);
}
创建一个静态方法,把每一个字符串分成一个个字符,并放入Stream流中:
//创建一个静态方法,把每一个字符串分成一个个字符,并放入Stream流中
public static Stream<Character> filterCharacter(String str){
//创建一个空的list集合用于存放字符串分解后的字符
List<Character> list=new ArrayList<>();
//字符串分成一个个字符进行遍历
for (Character character : str.toCharArray()) {
list.add(character);
}
return list.stream();//返回这个存放字符串分解后的字符的集合创建的stream流
}
我们使用map中间操作去调用这个静态方法
//使用map映射中间操作
@Test
public void test2(){
Stream<Stream<Character>> stream=list.stream()
.map(Stream_3::filterCharacter);
//stream.forEach(System.out::println);//获取到的是静态方法中返回的字符集流对象,所以遍历出来是流的内存地址
进行遍历
//双重遍历,先遍历list的流,然后对list流中的元素流继续遍历
stream.forEach((sm)->sm.forEach(System.out::println));
}
使用map去调用上面这个静态方法,返回的是一个stream流对象中子stream流对象中存放的拆分的字符串,而我们接下来使用的flatmap去调用这个静态方法,返回的是一个一个stream流对象中被才分的字符串的一个个小的子stream流对象
使用flatmap去调用静态方法遍历
//但是我们使用flatmap中间操作,就可以直接把返回值为流中的值直接转换为流
@Test
public void test3(){
Stream<Character> stream=list.stream()
.flatMap(Stream_3::filterCharacter);
stream.forEach(System.out::println);
}
虽然map和flatmap展现出来的结果是一样的,但是真正的来说,flatmap返回的是一个stream流对象中拆分的字符,而map遍历出来的确实stram流对象的子stream流对象中的拆分字符(自己的理解,有不对的地方一定要指出来啊~)
中间操作:3.排序
- 创建一个对象集合
//创建一个Enployee类型的list集合
List<Enployee> enploy=Arrays.asList(
new Enployee(1,"杨忠梁",20,100000),
new Enployee(2,"小杨",21,200000),
new Enployee(3,"刘俊",20,2000),
new Enployee(4,"坐邓伟",20,3000),
new Enployee(5,"皮奥迪",20,4000),
new Enployee(5,"皮奥迪",20,4000)
);
- 使用sorted自然排序
@Test
public void test1(){
//自然排序
List<String> list=Arrays.asList("bbb","aaa","ddd","ccc");
Stream<String> stream = list.stream();
stream.sorted()
.forEach(System.out::println);
}
- 使用定制排序
@Test
public void test2(){
//定制排序
Stream<Enployee> stream = enploy.stream();
stream.sorted((e1,e2)->{
if(e1.getAge().equals(e2.getAge())){
return e1.getSalary().compareTo(e2.getSalary());
}else{
return e1.getAge().compareTo(e2.getAge());
}
})
.forEach(System.out::println);
}