什么是Stream流?
在Java 8中,得益于Lambda所带来的函数式编程, 引入了一个全新的Stream流概念。
目的:用于简化集合和数组操作的API。
Stream流式思想的核心:
先得到集合或者数组的Stream流(就是一根传送带)
把元素放上去
然后就用这个Stream流简化的API来方便的操作元素。
Stream流的三类方法
获取Stream流
创建一条流水线,并把数据放到流水线上准备进行操作
中间方法
流水线上的操作。一次操作完毕之后,还可以继续进行其他操作。
终结方法
一个Stream流只能有一个终结方法,是流水线上的最后一个操作
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/*Stream<T> filter(Predicate<? super T> predicate) 用于对流中的数据进行过滤。
Stream<T> limit(long maxSize) 获取前几个元素
Stream<T> skip(long n) 跳过前几个元素
Stream<T> distinct()去除流中重复的元素。依赖(hashCode和equals方法)
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流*/
/*Stream<T> filter(Predicate<? super T> predicate)
返回由与此给定谓词匹配的此流的元素组成的流。*/
public class Stream_01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"lynk&co", "zeeker", "lotus", "polarstar");
list.forEach(System.out::println);//forEach结合lambda表达式对集合的遍历
System.out.println("=============");
/*stream流 的一些基本使用 支持链式编程*/
list.stream().filter(s -> s.startsWith("l")).forEach(System.out::println);
System.out.println("=============");
list.stream().filter(s -> s.startsWith("l")).filter(s -> s.length() > 6).forEach(System.out::println);
Set<String> set = new HashSet<>();
set.addAll(list);
System.out.println("=============");
System.out.println(set);
}
}
运行结果:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
/*Stream<T> filter(Predicate<? super T> predicate) 用于对流中的数据进行过滤。
Stream<T> limit(long maxSize) 获取前几个元素
Stream<T> skip(long n) 跳过前几个元素
Stream<T> distinct()去除流中重复的元素。依赖(hashCode和equals方法)
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
Stream<T> filter(Predicate<? super T> predicate)*/
/*static <T> Stream<T> of(T... values)
返回其元素为指定值的顺序有序流。
参数类型
T - 流元素的类型
参数
values - 新流的元素
结果
新流*/
public class Stream_02 {
public static void main(String[] args) {
List<String> listComputer = new ArrayList<>();
listComputer.add("数据结构");
listComputer.add("计算机科学概论");
listComputer.add("操作系统");
listComputer.add("计算机组成原理");
listComputer.add("软件工程");
listComputer.add("软件测试");
listComputer.add("软件测试");
listComputer.add("计算机网络");
listComputer.add("数字逻辑设计");
listComputer.add("数字逻辑设计");
System.out.println(listComputer);
/*使用stream流 startsWith() 方法筛选出以计算开头的数据并且用forEach输出出来*/
listComputer.stream().filter(s -> s.startsWith("计算")).forEach(s -> System.out.print(s + " "));
System.out.println();
System.out.println("============");
/*使用stream流 startsWith() 方法筛选出以计算开头的数据并且去重 跳过一个元素 把剩下的元素用forEach输出出来*/
listComputer.stream().filter(s -> s.startsWith("计算")).distinct().skip(1).forEach(s -> System.out.print(s + " "));
System.out.println();
System.out.println("============");
/*使用stream流 distinct() 方法 给集合的元素去重*/
listComputer.stream().distinct().forEach(s -> System.out.print(s + " "));
System.out.println();
System.out.println("============");
/*使用stream流map()方法 对流中的内容进行操作 (lambda表达式简化代码)*/
/*<R> Stream<R> map(Function<? super T,? extends R> mapper)
返回一个流,该流包含将给定函数应用于此流的元素的结果。*/
listComputer.stream().map(s -> "计算机基础课程 ;" + s).forEach(System.out::println);
System.out.println("============");
/*以下是未经过lambda表达式简化的原始代码*/
// listComputer.stream().map(new Function<String, Object>() {
// @Override
// public Object apply(String s) {
// return "计算机基础课程 : " + s;
// }
// }).forEach(t -> System.out.println(t));
List<String> listMath = new ArrayList<>();
Collections.addAll(listMath, "高等数学", "线性代数", "概率论与数理统计");
Stream streamComputer = listComputer.stream();
Stream streamMath = listMath.stream();
/*Stream流先对第一个流去重 然后用 静态方法concat() 拼接两个流*/
/*static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)*/
//concat()方法用于拼接两个流
Stream.concat(streamComputer,streamMath).distinct().forEach(s -> System.out.print(s + " "));
/*注意:Stream流创建之后只能使用一次后自动销毁 想要再次使用只能重新创建 再次使用在运行时会报错*/
// 需求 :以上两个集合的课程加工成Lesson对象,
Stream streamComputer1 = listComputer.stream();
Stream streamMath1 = listMath.stream();
ArrayList<Lesson> listLesson = new ArrayList<>();
/*第一种自己的方法,用forEach遍历,略low*/
Stream.concat(streamComputer1,streamMath1).forEach(s -> listLesson.add(new Lesson(s.toString())));
System.out.println();
System.out.println("============");
System.out.println(listLesson);
/*第二种方法,用map遍历*/
Stream streamComputer2 = listComputer.stream();
Stream streamMath2 = listMath.stream();
Stream.concat(streamComputer2,streamMath2).map(s -> new Lesson(s.toString())).forEach(System.out::println);
System.out.println("==============");
/*static <T> Stream<T> of(T... values)
返回其元素为指定值的顺序有序流。*/
Stream<String> s = Stream.of("Javase", "JavaWeb");
s.forEach(t -> System.out.println(t));
}
}
class Lesson{
private String name;
public Lesson(String name) {
this.name = name;
}
@Override
public String toString() {
return "Lesson{" +
"name='" + name + '\'' +
'}';
}
}
运行结果:
//需求:某个公司的开发部门,分为开发一部和二部,现在需要进行年中数据结算。
// 分析:
// :员工信息至少包含了(名称、性别、工资、奖金(假设每月都有奖金)、处罚记录)
// :开发一部有4个员工、开发二部有5名员工
// :分别筛选出2个部门的最高工资的员工信息,封装成优秀员工对象Topperformer
// :分别统计出2个部门的平均月收入,要求去掉最高和最低工资。
// :统计2个开发部门整体的平均工资,去掉最低和最高工资的平均值。
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Test {
public static double allOneSalary;
public static double allTwoSalary;
public static double allSalary;
public static void main(String[] args) {
List<Employee> one = new ArrayList<>();
one.add(new Employee("猪八戒", '男', 30000, 25000, null));
one.add(new Employee("孙悟空", '男', 25000, 1000, "顶撞上司"));
one.add(new Employee("沙僧", '男', 20000, 20000, null));
one.add(new Employee("小白龙", '男', 20000, 25000, null));
List<Employee> two = new ArrayList<>();
two.add(new Employee("武松", '男', 15000, 9000, null));
two.add(new Employee("李逵", '男', 20000, 10000, null));
two.add(new Employee("西门庆", '男', 50000, 100000, "被打"));
two.add(new Employee("潘金莲", '女', 3500, 1000, "被打"));
two.add(new Employee("武大郎", '女', 20000, 0, "下毒"));
// /*获得两个组的最高工资的员工*/
// 第一种写法 用sorted定义递减 比较规则 取第一个元素,用get()方法从流中获得这个元素(类型为Employee)
Employee ee1 = one.stream().sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary()))).findFirst().get();
Employee ee2 = two.stream().sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary()))).findFirst().get();
System.out.println("一组的最高工资员工的信息为: " + ee1);
System.out.println("二组的最高工资员工的信息为: " + ee2);
// 也可以如下写法 把以上的sorted换成 max 直接用get方法取元素即可
Employee e1 = one.stream().max((o1, o2) -> Double.compare((o1.getBonus() + o1.getSalary()), (o2.getBonus() + o2.getSalary()))).get();
System.out.println(e1);
Employee e2 = two.stream().max((o1, o2) -> Double.compare((o1.getBonus() + o1.getSalary()), (o2.getBonus() + o2.getSalary()))).get();
System.out.println(e2);
// /*筛选出2个部门的最高工资的员工信息,封装成优秀员工对象Topperformer*/
Stream.concat(one.stream()
.sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
.findFirst().stream(), two.stream()
.sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
.findFirst().stream()).map(s -> new Topperformer(s.getName(), s.getSalary() + s.getBonus()))
.forEach(System.out::println);
// /*分别统计出2个部门的平均工资,要求去掉最高和最低工资*/
/*临时变量allSalary,allOneSalary和allTwoSalary都定义在 main方法外面,类里面*/
/* 原因: 1:定义在main里面的话,匿名类对象访问不到,因为匿名类也是一个方法,main方法的变量进不去
2:定义在匿名类对象里面的话,因为是局部变量,参数不能带到main方法里面去*/
// System.out.println("以下是一组工资排序");
// one.stream()
// .sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
// .forEach(a -> System.out.println(a.getSalary() + a.getBonus()));
// System.out.println("以上是一组工资排序");
one.stream()
.sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
.skip(1).limit(one.size() - 2).forEach(s -> allOneSalary += (s.getSalary() + s.getBonus()));
// System.out.println("开发一部的总工资" + allOneSalary);
System.out.println("开发一部的平均月收入为: " + allOneSalary / (one.size() - 2));
// System.out.println("以下是二组工资排序");
// two.stream()
// .sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
// .forEach(a -> System.out.println(a.getSalary() + a.getBonus()));
// System.out.println("以上是二组工资排序");
two.stream()
.sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
.skip(1).limit(one.size() - 2).forEach(s -> allTwoSalary += (s.getSalary() + s.getBonus()));
// System.out.println("开发二部的总工资" + allTwoSalary);
System.out.println("开发二部的平均月收入为: " + allTwoSalary / (one.size() - 2));
// 统计2个开发部门整体的平均工资,去掉最低和最高工资的平均值
BigDecimal bd = new BigDecimal(one.size() + two.size() - 2);
Stream.concat(one.stream(), two.stream())
.sorted((o1, o2) -> Double.compare((o2.getBonus() + o2.getSalary()), (o1.getBonus() + o1.getSalary())))
.skip(1).limit(one.size() + two.size() - 2).forEach(s -> allSalary += (s.getSalary() + s.getBonus()));
BigDecimal bd3 = new BigDecimal(allSalary);
System.out.println("开发部所有人的平均月收入为: " + bd3.divide(bd, 2, RoundingMode.HALF_UP));
}
}
public class Employee {
private String name;
private char sex;
private double salary;
private double bonus;//假设每月都有奖金
private String punish; // 处罚信息
public Employee() {
}
public Employee(String name, char sex, double salary, double bonus, String punish) {
this.name = name;
this.sex = sex;
this.salary = salary;
this.bonus = bonus;
this.punish = punish;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public double getBonus() {
return bonus;
}
public void setBonus(double bonus) {
this.bonus = bonus;
}
public String getPunish() {
return punish;
}
public void setPunish(String punish) {
this.punish = punish;
}
public double getTotalSalay() {
return salary * 12 + bonus;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sex=" + sex +
", salary=" + salary +
", bonus=" + bonus +
", punish='" + punish + '\'' +
'}' + "\n";
}
}
public class Topperformer {
private String name;
private double money; // 月薪
public Topperformer() {
}
public Topperformer(String name, double money) {
this.name = name;
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Topperformer{" +
"name='" + name + '\'' +
", money=" + money +
'}';
}
}
运行结果:
把Stream流操作后的结果数据转回到集合或者数组中去
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/*可以把Stream流操作后的结果数据转回到集合或者数组中去。
public static <T> Collector toList()
public static <T> Collector toSet()
public static Collector toMap(Function keyMapper , Function valueMapper)
*/
public class StreamToCollection {
public static void main(String[] args) {
List<String> computerLesson = new ArrayList<>();
computerLesson.add("数据结构");
computerLesson.add("计算机科学概论");
computerLesson.add("操作系统");
computerLesson.add("计算机组成原理");
computerLesson.add("软件工程");
computerLesson.add("软件测试");
computerLesson.add("软件测试");
computerLesson.add("计算机网络");
computerLesson.add("数字逻辑设计");
computerLesson.add("数字逻辑设计");
System.out.println(computerLesson);
/*用List集合接收,Stream流*/
List<String>list = computerLesson.stream().distinct().collect(Collectors.toList());
System.out.println(list);
/*用Set集合接收,Stream流*/
Set<String> set = computerLesson.stream().collect(Collectors.toSet());
// 简化后的语句: Set<String> set = new HashSet<>(computerLesson);
System.out.println(set);
/*用数组接收 Stream流*/
Object arr [] = computerLesson.stream().toArray();
System.out.println(Arrays.toString(arr));
}
}
运行结果: