一、Stream API
1.为什么要使用Stream API?
实际开发中,需要操作的数据大都来自于mysql或Oracle等关系数据库,还有的数据库如Redis、MongDB,对于这些非关系数据库的操作就需要Java层面处理(Stream API)。
2.Stream和Collection集合的区别?
Collectio是一种静态的数据内存结构,面向内存,存储在内存中;而Stream是有关计算的,面向CPU,通过CPU计算处理。
3.什么是Stream API?
是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,Stream讲的是计算!”
注意:
① stream自己不会存储元素;
② Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream;
③ Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
4.Stream操作的三步骤
(1)创建Stream
一个数据源(如:集合、数组),获取一个流
(2)中间操作
一个中间操作链(多个操作),对数据源的数据进行处理
(3)终止操作(终端操作)
一旦执行终止操作,就执行中间操作链,并产生结果。之后不会再被使用
(1)创建Stream的四种方式:
@Test
public void test01(){
//创建Stream方式一:使用集合
List<String> list = Arrays.asList("北京", "上海", "广州", "深圳");
//default Stream<E> stream():返回一个顺序流
Stream<String> stream = list.stream();
//default Stream<E> parallelStream():返回一个并行流
Stream<String> stringStream = list.parallelStream();
//创建Stream方式二:使用数组
String[] arr = new String[]{"Java","Python","PHP","C++","GO"};
//调用Arrays的public static <T> Stream<T> stream(T[] array):返回一个流
Stream<String> stream1 = Arrays.stream(arr);
//创建Stream方式三:使用Stream的of()
Stream<Integer> stream2 = Stream.of(12, 5, 8, 46);
//创建stream方式四:创建无限流(了解)
//迭代(遍历前十个偶数)
//public static<T> Stream<T> iterate(final T seed,final Unaryoperator<T> f)
Stream.iterate(0,t->t+2).limit(10).forEach(System.out::println);
//生成
//public static<T>Stream<T> generate(Supplier<T> s)
Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
(2)Stream的中间操作
//User类只是一个JavaBean
public class User {
private int id;
private String name;
private int age;
private double salary;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public double getSalary() { return salary; }
public void setSalary(double salary) { this.salary = salary; }
public User() { }
public User(int id, String name, int age, double salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
"name='" + name +
", age=" + age +
", salary=" + salary +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id == user.id &&
age == user.age &&
Double.compare(user.salary, salary) == 0 &&
Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, age, salary);
}
public static List<User> getUsers(){
ArrayList<User> users = new ArrayList<>();
users.add(new User(1001,"马云",36,600.05));
users.add(new User(1002,"乔布斯",34,800.23));
users.add(new User(1003,"马化腾",31,599.35));
users.add(new User(1004,"雷军",25,450.21));
users.add(new User(1005,"任正非",46,756.35));
users.add(new User(1006,"比尔盖茨",50,960.87));
users.add(new User(1007,"李彦宏",26,630.31));
users.add(new User(1008,"扎克伯格",18,265.45));
users.add(new User(1008,"扎克伯格",18,265.45));
return users;
}
}
① 筛选与切片
//1.筛选与切片
@Test
public void test01(){
List<User> users = User.getUsers();
Stream<User> stream = users.stream();
//1.查询User的salary大于700的User信息
//filter(Predicate p)——接收Lambda:从流中过滤某些元素
stream.filter(u -> u.getSalary() > 700).forEach(System.out::println);
System.out.println("--------------------------------------------------");
//2.limit(n)——截断流:使其输出的元素不超过指定数量
users.stream().limit(2).forEach(System.out::println);
System.out.println("--------------------------------------------------");
//3.skip(n)——跳过元素:返回一跳过前面的n个元素的流,若不足,返回一个空流
users.stream().skip(5).forEach(System.out::println);
System.out.println("--------------------------------------------------");
//4.distinct()——去重:通过流生成的hashcode()和equals()去除重复元素
users.stream().distinct().forEach(System.out::println);
}
② 映射
//2.映射
@Test
public void test02(){
//map(Function f):接受一个函数作为参数,将函数转换成其他提取信息,该函数会被应用于每个元素上,并将其映射成一个新的元素
List<String> list = Arrays.asList("GG", "BB", "MM", "DD");
//将集合list中的元素转换为小写并遍历输出
list.stream().map(str -> str.toLowerCase()).forEach(System.out::println);
//练习:查找User中名字大于三位的User
List<User> users = User.getUsers();
Stream<String> nameStream = users.stream().map(User::getName);
nameStream.filter(name -> name.length()>3).forEach(System.out::println);
//flatMap(Function f):接收一个函数作为参数,将流中的每个值转换为另一个流,然后把所有的流连接成一个流
Stream<Character> characterStream = list.stream().flatMap(StreamTest::stringToStream);
characterStream.forEach(System.out::println);
}
//将字符串中的多个字符构成的集合转换为对应的Stream的实例
public static Stream<Character> stringToStream(String str){
ArrayList<Character> list = new ArrayList<>();
for(Character ch : str.toCharArray()){
list.add(ch);
}
return list.stream();
}
③ 排序
//3.排序
@Test
public void test03(){
//数组排序
List<Integer> list = Arrays.asList(18, 25, 36, 22, 10,-2);
list.stream().sorted().forEach(System.out::println);
// //抛异常java.lang.ClassCastException,原因User未实现Comparable接口
// List<User> users = User.getUsers();
// users.stream().sorted().forEach(System.out::println);//自然排序
//对象排序
List<User> users = User.getUsers();
users.stream().sorted((u1, u2) -> {
int ageValue = Integer.compare(u1.getAge(), u2.getAge());//age正序
if(ageValue!=0){
return ageValue;
}else{
return Double.compare(u1.getSalary(),u2.getSalary());//salary正序
}
}).forEach(System.out::println);
System.out.println();
}
(2)Stream的终止操作
① 匹配与查找
//① 匹配与查找
@Test
public void test01(){
List<User> users = User.getUsers();
//allMatch(Predicate p)——检查是否匹配所有元素。练习:是否所有的员工的年龄都大于20
boolean b = users.stream().allMatch(u -> u.getAge() > 20);
System.out.println(b);//false
System.out.println("--------------------------------------------------");
//anyMatch(Predicate p)——检查是否至少匹配一个元素。练习:是否存在员工的工资大于500
boolean b1 = users.stream().anyMatch(u -> u.getSalary() > 500);
System.out.println(b1);
System.out.println("--------------------------------------------------");
//noneMatch(Predicate p)——检查是否没有匹配的元素。练习:是否存在员工姓"雷”
boolean b2 = users.stream().noneMatch(u -> u.getName().startsWith("任"));
System.out.println(b2);
System.out.println("--------------------------------------------------");
//findFirst——返回第一个元素
Optional<User> first = users.stream().findFirst();
System.out.println(first);
System.out.println("--------------------------------------------------");
//findAny——返回当前流中的任意元素
Optional<User> any = users.stream().findAny();
System.out.println(any);
System.out.println("--------------------------------------------------");
//count——返回流中元素的总个数
long count = users.stream().count();
System.out.println(count);
System.out.println("--------------------------------------------------");
//max (Comparator c)——返回流中最大值 练习:返回最高的工资
Stream<Double> doubleStream = users.stream().map(u -> u.getSalary());
Optional<Double> max = doubleStream.max(Double::compare);
System.out.println(max);
System.out.println("--------------------------------------------------");
//min( Comparator c)——返回流中最小值 练习:返回最低工资的员工
Optional<User> minUser = users.stream().min((u1, u2) -> Double.compare(u1.getSalary(), u2.getSalary()));
System.out.println(minUser);
System.out.println("--------------------------------------------------");
//forEach(Consumer c)——内部迭代
users.stream().forEach(System.out::println);
System.out.println("--------------------------------------------------");
// //使用集合的遍历操作
// users.forEach(System.out::println);
}
② 归约
//② 归约
@Test
public void test02(){
//reduce(T identity,Binaryoperator)——可以将流中元素反复结合起来,得到一个值,返回一个T。练习1:计算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);
//reduce(Binaryoperator)——可以将流中元素反复结合起来,得到一个值。返回Optional<T> 练习2:计算公司所有员工工资的总和
List<User> users = User.getUsers();
Stream<Double> doubleStream = users.stream().map(User::getSalary);
// Optional<Double> sumSalary = doubleStream.reduce(Double::sum);//Double中的public static double sum(double a, double b)
Optional<Double> sumSalary = doubleStream.reduce((d1, d2) -> d1 + d2);
System.out.println(sumSalary);
}
③ 收集
//③ 收集
@Test
public void test03(){
//collect(collector c)-将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中的元素做汇总的方法
//练习1:查找工资大于700的员工,结果返回为一个List或Set
List<User> users = User.getUsers();
List<User> userList = users.stream().filter(u -> u.getSalary() > 700).collect(Collectors.toList());
userList.forEach(System.out::println);
System.out.println("------------------------------------------------");
Set<User> userSet = users.stream().filter(u -> u.getSalary() > 700).collect(Collectors.toSet());
userSet.forEach(System.out::println);
}
二、Optional类
Optional< T >类(java.util.Optional)是一个容器类, 为了避免避免空指针异常而出现的。
Optional类的Javadoc描述如下:这是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
public class Boy {
private Girl girl;
public Boy() {
}
public Boy(Girl girl) {
this.girl = girl;
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {
this.girl = girl;
}
@Override
public String toString() {
return "Boy{" +
"girl=" + girl +
'}';
}
}
class Girl {
private String name;
public Girl() {
}
public Girl(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
'}';
}
}
@Test
public void test01(){
Girl girl = new Girl();
//Optional.of(T t) :创建一个Optional实例,t必须非空
//Optional.empty() : 创建一个空的Optional实例
Optional<Girl> girl1 = Optional.of(girl);
System.out.println(girl1);
//Optional.ofNullable(T t): t可以为null
girl = null;
Optional<Girl> girlOptional = Optional.ofNullable(girl);
System.out.println(girlOptional);
//orElse(T t1):如果单前的optional内部封装的t是非空的,则返回内部的t.如果内部的是空的,则返回orElse()方法中的参数t1.
Girl girl2 = girlOptional.orElse(new Girl("赵敏"));
System.out.println(girl2);
}
@Test
public void test02(){
Boy boy = new Boy();//情况一:boy为空,girl为空
boy = null;
String girl = getGirl(boy);
System.out.println(girl);
Boy boy1 = new Boy();//情况二:boy非空,girl为空
String girl1 = getGirl(boy1);
System.out.println(girl1);
Boy boy2 = new Boy(new Girl("赵敏"));
String girl2 = getGirl(boy2);
System.out.println(girl2);
}
public String getGirl(Boy boy){
Optional<Boy> optionalBoy = Optional.ofNullable(boy);
//此时的boy一定非空
Boy boy1 = optionalBoy.orElse(new Boy(new Girl("周芷若")));
Girl girl = boy1.getGirl();
Optional<Girl> optionalGirl = Optional.ofNullable(girl);
//此时的girl一定非空
Girl girl1 = optionalGirl.orElse(new Girl("小昭"));
return girl1.getName();
}