❤️java8有两大重要的改变,第一个是我们前面讲的
Lambda表达式
,另一个就是我们即将要介绍的Stream API(java.util.stream)
,Stream API
真正的把函数式编程风格
引入到java中。
❤️简言之,Stream API提供了一种高效且易于使用的处理数据的方式。
⛄️ 一、什么是Stream呢
stream
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列
注意:
☀️(1)stream
自己不会存储元素。
☀️(2)stream
不会改变源对象
,相反它会返回一个持有结果的新Stream
。
☀️(3)stream
操作是延迟执行的,这意味着它们等到需要结果的时候才执行。
说到延迟,就涉及到stream操作的三个步骤。
⛄️二、Stream的操作
⭐️ 1.创建Stream
一个数据源(集合,数组等),获取一个流。
详细过程请看以下代码:
public class StreamAPICreate {
//java8中Collection接口被扩展,提供了两个获取流的方法。
//创建Stream方式一:通过集合
public void Test1(){
//先获得一个集合。
List<Employ> employs = EmployData.getEmploy();
//Stream<E> stream(): 返回一个顺序流。
Stream<Employ> stream = employs.stream();
//Stream<E> parallelStream(): 返回一个并行流。
Stream<Employ> parallelStream = employs.parallelStream();
}
//java8中Arrays的静态方法stream()可以获取数组流。
//创建Stream方式二:通过数组
public void Test2(){
//先创建一个数组。
int[] a = new int[]{1,2,3,4,5,6};
//static <T>Stream<T> stream(T[] array):返回一个流。
IntStream stream = Arrays.stream(a);
}
//创建Stream方式三:通过Stream类的of():通过显示值创建一个流。
//它可以接受任意数量的参数。
//static<T>Stream<T> of(T.......value)
public void Test3(){
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6);
}
}
说明:(1):以上代码,中涉及到自定义的Employ
和EmployData
类,所以下面我会将这两个类的内容展现出来,以便于大家理解以上代码。
public class Employ {
public String getName() {
return name;
}
public String name;
public int getId() {
return id;
}
public int id;
public int age;
public Double getSalary() {
return salary;
}
public int getAge() {
return age;
}
public double salary;
public Employ() {
System.out.println("123");
}
@Override
public String toString() {
return "Employ{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
", salary=" + salary +
'}';
}
public Employ(int id, String name, int age, double salary){
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public class EmployData {
public static List<Employ> getEmploy(){
List<Employ> list = new ArrayList<>();
list.add(new Employ(1001,"马化云",43,10000));
list.add(new Employ(1002,"刘强宏",48,50000));
list.add(new Employ(1003,"马腾",55,6500));
list.add(new Employ(1004,"李彦东",15,20000));
return list;
}
}
(2):本来还有第四种方式来创建Stream流,但是由于不常用,这里就没有介绍。
⭐️2.中间操作
废话不多说,详见代码
public class StreamAPITest {
//筛选与切片
@Test
public void Test1() {
List<Employ> list = EmployData.getEmploy();
Stream<Employ> stream = list.stream();
//filter(Predicate p)-接受Lambda从流中排除某些元素
//示例:查询id大于1002的元素.
stream.filter(e -> e.getId() > 1002).forEach(System.out::println);
System.out.println("=========================================");
//limit(n)-截断流,使其元素不超过给定数量。
list.stream().limit(3).forEach(System.out::println);
System.out.println("=========================================");
//skip(n)-跳过n个元素。
list.stream().skip(3).forEach(System.out::println);
System.out.println("=========================================");
}
//映射
@Test
public void Test2() {
//map(Function f)---接收一个函数作为参数,将元素转换成其他形式或提取信息,
//该函数会被应用到每个元素上,并将其映射成一个新的元素
//练习1:将小写字母转换为大写字母(元素转换成其他形式)
List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
System.out.println("=============================");
//练习2:获取员工姓名长度大于2的员工的姓名(提取信息)
List<Employ> employ = EmployData.getEmploy();
Stream<String> stringStream = employ.stream().map(Employ::getName);
stringStream.filter(n -> n.length() > 2).forEach(System.out::println);
System.out.println("=============================");
//练习3:
Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest::fromStringToStream);
streamStream.forEach(s -> {
s.forEach(System.out :: println);
});
System.out.println("=============================");
//flatMap(Function f)---接收一个函数作为参数,将流中的每个值都换成另一个流
//然后把所有流连接成一个流
Stream<Character> characterStream = list.stream().flatMap(StreamAPITest::fromStringToStream);
characterStream.forEach(System.out :: println);
}
public static Stream<Character> fromStringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for(Character c : str.toCharArray()){
list.add(c);
}
return list.stream();
}
//排序
@Test
public void Test3(){
//sorted()---自然排序
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().sorted().forEach(System.out :: println);
System.out.println("=========================");
//sorted(Comparator com)---定制排序
List<Employ> employ = EmployData.getEmploy();
employ.stream().sorted((e1,e2) -> Integer.compare(e1.getId(),e2.getId())).forEach(System.out :: println);
}
}
⭐️ 3.终止操作
public class StreamAPITest1 {
//1.匹配与查找
@Test
public void Test1(){
//allMatch(Predicata p)——检查是否匹配所有元素。
//练习:是否所有的员工的年龄都大于18。
List<Employ> employ = EmployData.getEmploy();
boolean b = employ.stream().allMatch(e -> e.getAge() > 18);
System.out.println(b);
System.out.println("======================");
//anyMatch(Predicate p)——检查是否至少匹配一个元素。
//练习:是否存在员工工资大于10000的。
boolean b1 = employ.stream().anyMatch(e -> e.getSalary() > 10000);
System.out.println(b1);
System.out.println("======================");
//noneMatch(Predicata p)——检查是否没有匹配的元素。
//练习:是否存在姓王的员工
boolean b2 = employ.stream().noneMatch(e -> e.getName().startsWith("王"));
System.out.println(b2);
System.out.println("======================");
//findFirst()——返回第一个元素。
Optional<Employ> first = employ.stream().findFirst();
System.out.println(first);
//findAny()——返回当前流中的任意元素。
Optional<Employ> any = employ.stream().findAny();
System.out.println(any);
}
@Test
public void test2(){
//count()--返回流中元素的总个数。
List<Employ> employ = EmployData.getEmploy();
long count = employ.stream().filter(e -> e.getSalary() > 5000).count();
System.out.println(count);
System.out.println("======================");
//max(Comparator com)---返回流中最大值。
//练习:返回最高的工资。
Stream<Double> doubleStream = employ.stream().map(e -> e.getSalary());
Optional<Double> max = doubleStream.max(Double :: compare);
System.out.println(max);
System.out.println("======================");
//min(Comparator com)---返回流中最小值。
//练习:返回最低的工资。
Optional<Employ> min = employ.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(min);
System.out.println("======================");
//forEach(Consumer con)。----最熟悉不过了。
employ.stream().forEach(System.out :: println);
}
//2.规约
@Test
public void Test3(){
//reduce(T identity,BinaryOperator)---可以将流中的元素反复结合起来,得到一个值,返回
//练习:计算1-10的自然数的和
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, Integer::sum);
System.out.println(sum);
System.out.println("======================");
//reduce(BinaryOperator)---可以将流中的元素反复结合起来,得到一个值
//练习:计算公司所有员工工资.
List<Employ> employ = EmployData.getEmploy();
Stream<Double> doubleStream = employ.stream().map(e1 -> e1.getSalary());
Optional<Double> re = doubleStream.reduce(Double::sum);
System.out.println(re);
}
//3.收集
@Test
public void Test4(){
//collect(Collector c)---将流转换为其他形式,接受一个Collector接口的实现,
//用于给Stream流中元素做汇总的方法。
//练习:查找工资大于6000的员工,返回list或set。
//list
List<Employ> employ = EmployData.getEmploy();
List<Employ> collect = employ.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
collect.forEach(System.out :: println);
System.out.println("=====================");
//set
Set<Employ> collect1 = employ.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
collect1.forEach(System.out :: println);
}
}
注意:一旦执行了终止操作就不能
再执行中间操作了。