java 函数式编程

函数式编程是一种编程范式,它将计算机过程视为一系列函数的组合,函数式编程强调使用不可变的数据和没有副作用的的纯函数进行编程。Java的函数式编程就是使用函数式编程的风格,使用lambda表达式和函数时接口实现,Java8引入了内置的函数式接口:Function,Predicate,Consumer等。

Lambda

Lambda表达式代码简洁,只能创建只有一个抽象方法的接口,Lambda表达式由三部分组成:

  • 形参列表:形参列表可以省略参数类型,如果只有一个参数,括号也可以省略。
  • 箭头(->):英文中画线和大于符号组成。
  • 代码块:代码块只有一条语句,可以省略代码块的花括号,只有一个return语句。可以省略return。

格式:

(形参列表)->{
    代码块
}

下面举例:

先使用匿名内部类的方式:

简化为lambda表达式:

package com.example.springBootMyBatis.pojo;

import lombok.Getter;

/**
 * @author 赵东洋
 * @date 2023/10/25
 */
@Getter
public class Tets {
    private String name;

    public static void main(String[] args) {
        new Thread(() -> System.out.println("这是Lambda的方式"));
    }
}

可以看到,代码省略为一行,Lambda注重对数据的操作。

下面做个练习:

先使用匿名内部类的方式,我们自定义了一个方法calculateNum,calculateNum的参数是IntBinaryOperator接口,该接口只有一个抽象方法,在main方法中调用的时候,使用匿名内部类的方式。

package com.example.springBootMyBatis.pojo;

import lombok.Getter;

import java.util.function.IntBinaryOperator;

/**
 * @author 赵东洋
 * @date 2023/10/25
 */
@Getter
public class Tets {
    private String name;

    public static void main(String[] args) {
        int i = calculateNum(new IntBinaryOperator() {
            @Override
            public int applyAsInt(int left, int right) {
                // 相乘
                return left * right;
            }
        });
        System.out.println(i);
    }

    public static int calculateNum(IntBinaryOperator intBinaryOperator) {
        int a = 10;
        int b = 20;
        return intBinaryOperator.applyAsInt(a, b);
    }

}

简化为Lambda表达式:

public class Tets {
    private String name;

    public static void main(String[] args) {
        int i = calculateNum((int a, int b) -> a + b);
        System.out.println(i);
    }

    public static int calculateNum(IntBinaryOperator intBinaryOperator) {
        int a = 10;
        int b = 20;
        return intBinaryOperator.applyAsInt(a, b);
    }

}

stream流

stream是用来对数组和集合进行链状和流式的操作,方便我们对数组和集合的操作。

代码准备

用户类,用户类下包含一个手机号类,一个用户可以拥有多个手机号。

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    /**
     * 用户Id
     */
    private Long userId;
    /**
     * 用户名
     */
    private String username;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 密码
     */
    private String password;
    /**
     * 邮箱
     */
    private String email;
    /**
     * 手机号
     */
    private List<CellPhoneNumber> phone;
}

用户的手机号类。

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CellPhoneNumber {
    /**
     * Id
     */
    private Long id;
    /**
     * 手机运营商:
     * 1. 电信
     * 2. 联通
     * 3. 移动
     */
    private String operator;
    /**
     * 电话号码
     */
    private String phoneNumber;
}

数据准备:

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
    }

    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11,"1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四",18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22,"1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一",27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

体验Stream流

打印所有年龄大于等于18的,去除重复的。

public class StreamTest {
    public static void main(String[] args) {
        // 需求1:打印所有年龄大于等于18的,去除重复的。
        getUserData().stream() // 将集合转换为流
                .distinct() //去除重复的元素
                .filter(user -> user.getAge() >= 18) // 条件是年龄等于大于18的,过滤掉了年龄小于18岁的。
                .forEach(user -> System.out.println(user.getUsername())); // 打印结果,只取名字
    }

    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

stream的常用操作:

创建流

单列集合:集合对象.stream();

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(1);
list.add(2);
list.add(3);
Stream<Integer> stream = list.stream();
stream.distinct().forEach(w -> System.out.println(w));

数组:Arrays.stream(数组)或者Arrays.of(数组)

int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 8};
// Arrays.stream(数组)的方式
Arrays.stream(a).distinct().forEach(w -> System.out.println(w));
// Arrays.of(数组)的方式
Stream<int[]> a1 = Stream.of(a);
a1.distinct().forEach(w -> System.out.println(Arrays.toString(Arrays.stream(w).toArray())));

双列集合:需要转化为单列集合后再创建

Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 22);
map.put("张三", 23);
// 转换为单列集合
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();
// 流操作,年龄大于22的,去除重复。
stream.distinct().filter(d->d.getValue()>22).forEach(w -> System.out.println(w));
// 也可以只对key或者value进行流创建
Map<String, Integer> map = new HashMap<>();
map.put("张三", 23);
map.put("李四", 22);
map.put("张三", 23);
Stream<String> stream1 = map.keySet().stream();
Stream<Integer> stream = map.values().stream();
stream1.forEach(w -> System.out.println(w));
stream.forEach(s -> System.out.println(s));

filter

可以对流中的数据进行过滤/筛选,符合条件的数据继续存在。

例如,获取集合中名字为"张三"的数据。

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
        getUserData().stream()
            .filter(d -> "张三".equals(d.getUsername()))
            .forEach(w -> System.out.println(w));
    }

    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

map

map操作用于将流中的每个元素按照给定的函数进行映射转换,然后将映射后的结果作为新的流元素返回。

例如:将每个用户的年龄*2。

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
        getUserData().stream()
            .distinct()
            .map(w -> w.getAge()*2)
            .forEach(w -> System.out.println(w));
    }

    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

例如:将用户的邮箱中的字母都修改为大写

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
        getUserData().stream()
            .distinct()
            .map(w -> w.getEmail().toUpperCase())
            .forEach(w -> System.out.println(w));
    }

    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

例如:获取用户手机号的运营商,并返回。

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
        getUserData().stream()
            .map(w -> w.getPhone())
            .map(p->p.stream().
                    map(w -> w.getOperator()))
            .forEach(w -> System.out.println(Arrays.toString(w.toArray())));
    }
    
    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

distinct

去除流中重复的元素

例如:获取所有用户,去除重复。

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
        getUserData().stream()
            .distinct()
            .forEach(System.out::println);
    }
    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

soted

对流中的元素进行排序。

sorted有两个抽象方法,一个没有参数,另一个需要传入参数:Comparator<? super T> comparator。没有参数的,直接根据获取到的流进行排序,这时候如果流的类型不是Comparator,会出现异常。

例如:

getUserData().stream()
        .sorted()
        .forEach(System.out::println);
会出现下面错误

这时候可以先使用map进行流转换,例如:

getUserData().stream()
        .map(w -> w.getAge())
        .sorted()
        .forEach(System.out::println);

也可以实现Comparator接口,例如:

package com.example.springBootMyBatis.stream;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Comparable<User> {
    /**
     * 用户Id
     */
    private Long userId;
    /**
     * 用户名
     */
    private String username;
    /**
     * 年龄
     */
    private Integer age;
    /**
     * 密码
     */
    private String password;
    /**
     * 邮箱
     */
    private String email;
    /**
     * 手机号
     */
    private List<CellPhoneNumber> phone;

    @Override
    public int compareTo(User o) {
        // 当前的age减去入参的age,就是升序
        return this.age-o.getAge();
    }
}
package com.example.springBootMyBatis.stream;

import java.util.*;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author 赵东洋
 * @date 2023/10/29
 */
public class StreamTest {
    public static void main(String[] args) {
        getUserData().stream()
                .sorted()
                .forEach(user -> System.out.println(user.getAge()));
    }

    public static List<User> getUserData() {
        // 初始化用户
        User user = new User(1L, "张三", 11, "1234567", "4234567@qq.com", null);
        User user1 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user5 = new User(2L, "李四", 18, "1234567", "1234567@qq.com", null);
        User user2 = new User(3L, "王二", 22, "1234567", "7234567@qq.com", null);
        User user3 = new User(4L, "李一", 27, "1234567", "5234567@qq.com", null);


        // 创建手机号集合
        ArrayList<CellPhoneNumber> cellPhoneNumbers = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers1 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers2 = new ArrayList<>();
        ArrayList<CellPhoneNumber> cellPhoneNumbers3 = new ArrayList<>();
        // 初始化手机号数据
        CellPhoneNumber cellPhoneNumber = new CellPhoneNumber(1L, "电信", "17723768909");
        CellPhoneNumber cellPhoneNumber1 = new CellPhoneNumber(2L, "联通", "19823768909");
        CellPhoneNumber cellPhoneNumber2 = new CellPhoneNumber(3L, "电信", "15823768909");
        CellPhoneNumber cellPhoneNumber3 = new CellPhoneNumber(4L, "联通", "19323768909");
        CellPhoneNumber cellPhoneNumber4 = new CellPhoneNumber(5L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber5 = new CellPhoneNumber(6L, "移动", "17523768909");
        CellPhoneNumber cellPhoneNumber6 = new CellPhoneNumber(7L, "移动", "18523768909");
        // 将手机号数据设置给手机号集合
        cellPhoneNumbers.add(cellPhoneNumber);
        cellPhoneNumbers.add(cellPhoneNumber1);
        cellPhoneNumbers1.add(cellPhoneNumber2);
        cellPhoneNumbers1.add(cellPhoneNumber3);
        cellPhoneNumbers2.add(cellPhoneNumber4);
        cellPhoneNumbers2.add(cellPhoneNumber5);
        cellPhoneNumbers3.add(cellPhoneNumber6);
        // 将手机号集合设置给用户
        user.setPhone(cellPhoneNumbers);
        user1.setPhone(cellPhoneNumbers1);
        user2.setPhone(cellPhoneNumbers2);
        user3.setPhone(cellPhoneNumbers3);
        // 缓存用户的集合
        ArrayList<User> users = new ArrayList<>();
        // 将用户添加到用户集合
        users.add(user);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        return users;
    }

}

运行结果:

User重写的Comparable接口,重写的方法,修改为降序。将this.age-o.getAge()修改为o.getAge()-this.age。

    @Override
    public int compareTo(User o) {
        // 当前的age减去入参的age,相减就是升序
        return o.getAge()-this.age;
    }

降序输出结果:

上面是没有参数的,咱们试一下有参数的:

升序:

getUserData().stream()
        .sorted((o1, o2) -> o1.getAge()-o2.getAge())
        .forEach(user -> System.out.println(user.getAge()));

降序:

        getUserData().stream()
                .sorted((o1, o2) -> o2.getAge()-o1.getAge())
                .forEach(user -> System.out.println(user.getAge()));

limit

可以限制获取的流数据数量。

例如:

获取年龄最小的前两个用户。

       getUserData().stream()
               .sorted((o1, o2) -> o1.getAge()-o2.getAge())
               .limit(2)
               .forEach(user -> System.out.println(user.getUsername()));

skip

跳过前n个元素。

例如:去除重复,获取所有的用户年龄,升序排列,去除前2个元素。

getUserData().stream()
        .distinct()
        .sorted((o1, o2) -> o1.getAge()-o2.getAge())
        .skip(2)
        .forEach(u-> System.out.println(u.getAge()));

flatMap

map可以把一个对象转换为另一个对象作为流中的元素,flatMap可以把一个对象转换为多个对象作为流中的元素。

例如:获取用户的手机号,去除重复,,打印供应商。

getUserData().stream()
        .flatMap(user -> user.getPhone().stream())
        .distinct()
        .forEach(user -> System.out.println(user.getOperator()));

forEach

遍历流中的数据。

例子:去除重复,获取所有用户的邮箱。

getUserData().stream()
        .distinct()
        .forEach(user -> System.out.println(user.getEmail()));

count

获取流中元素的个数

例子:获取手机号所有手机号的个数,去除重复。

long count = getUserData().stream()
        .flatMap(user -> user.getPhone().stream())
        .distinct()
        .map(phone->phone.getPhoneNumber())
        .distinct()
        .count();
System.out.println(count);

max&min

最大值,最小值。

例子:获取年龄的最大值。

Optional<Integer> max = getUserData().stream()
        .map(user -> user.getAge())
        .max((o1, o2) -> Math.toIntExact(o1 - o2));
System.out.println(max.get());

例子:获取年龄的最小值。

Integer integer = getUserData().stream()
    .map(user -> user.getAge())
    .min(Long::compare).get();
System.out.println(integer);

collect

将流收集为几个集合。

例子:获取一个数据为所有电话号码的集合。

toList:将数据转换为List集合。

List<String> collect = getUserData().stream()
        .flatMap(user -> user.getPhone().stream())
        .map(cellPhoneNumber -> cellPhoneNumber.getPhoneNumber())
        .collect(Collectors.toList());
System.out.println(collect);

例子:获取一个数据为所有邮箱的Set集合(Set集合是没有重复数据的.。

toSet:将数据转换为Set集合。

            Set<String> collect = getUserData().stream()
                .map(user -> user.getEmail())
                .collect(Collectors.toSet());
        System.out.println(collect);

例子:获取一个数据为Map的集合,用户名为key,密码是value。

toMap:将数据转换为Map集合。

Map<String, String> collect = getUserData().stream()
        .collect(Collectors.toMap(key -> key.getUsername(), value -> value.getPassword()));
System.out.println(collect);

anyMatch

匹配是否有符合的数据,符合返回true,不符合返回false。

例子:匹配是否有18岁以上的用户。

boolean b = getUserData().stream()
        .anyMatch(user -> user.getAge() > 18);
System.out.println(b);

allMatch

匹配所有的数据是否符合条件,符合为true,有一个符合的false。

例子:是否有180岁以下的用户。

boolean b = getUserData().stream()
        .allMatch(user -> user.getAge() < 180);
System.out.println(b);

noneMatch

判断流中所有的元素是否不合符条件,都不符合true,符合true

例子:用户中是否有年龄大与180的。

boolean b = getUserData().stream()
        .noneMatch(user -> user.getAge() > 180);
System.out.println(b);

findFirst

获取流中的第一个元素。

例子:获取年龄最大的用户

Optional<User> first = getUserData().stream()
        .sorted((o1, o2) -> o2.getAge()- o1.getAge())
        .findFirst();

first.ifPresent(user ->
        System.out.println(user.getAge()));

reduce

对流中的数据,按照我们自己的计算方式,得出一个结果。

例子:计算出所有用户的年龄和

Integer reduce = getUserData().stream()
        .map(user -> user.getAge())
        .reduce(0, (a, b) -> a + b);
System.out.println(reduce);

例子:获取所有用户中,年龄最大的用户。

Integer reduce = getUserData().stream()
        .map(user -> user.getAge())
        .reduce(Integer.MIN_VALUE, (a, b) -> a > b ? a : b);
System.out.println(reduce);

例子:获取所有用户中,年龄最小的用户。

Integer reduc1e = getUserData().stream()
        .map(user -> user.getAge())
        .reduce(Integer.MAX_VALUE, (a, b) -> a < b ? a : b);
System.out.println(reduc1e);

Optional

概述

一句话,解决NPE异常。

使用

optional就是把我们的数据封装到optional中,在使用他提供的方法操作封装到optional的数据,有效的避免NPE异常。

创建Optional的两种方式:

区别是:当传入的参数值不存在时,of方法会抛出NPE异常,ofNullable不会。

不建议使用Optional.of方法,除非你确定你传入的参数不是空。

Optional<List<User>> userData = Optional.ofNullable(getUserData());
Optional<List<User>> userData1 = Optional.of(getUserData());

一般我们获取数据,都是使用mybatis或者jpa从数据库查询到,这时候返回的数据类型一般都是Optional,可以直接使用。

Optional的get()方法可以获取到数据,但是不建议使用,使用这个方法,内部为空会出现异常。

Optional<User> user = Optional.ofNullable(getUser());
User user1 = user.get();

建议使用:

orElseGet:获取数据,并设置数据为空的默认值。不为空正常获取数据,为空根据参数的默认值设置为默认数据。

orElseThrow:不为空获取到数据,为空则根据自己设置的规则抛出异常。

User user2 = user.orElseGet(User::new);
System.out.println(user2.getAge());
public static Optional<User> getUser(){
    User user = new User(1L, "张三", null, "1234567", "4234567@qq.com", null);
    return Optional.ofNullable(null);
}
Integer age = user.orElseThrow(()->new RuntimeException("为空")).getAge();
System.out.println(age);

filter:过滤, 如果有数据,但是不符合我们的判断,也会变成一个无数据的Optiinal对象。

符合判断例子:

public static Optional<User> getUser(){
    User user = new User(1L, "张三", 23, "1234567", "4234567@qq.com", null);
    return Optional.ofNullable(user);
}
public static void main(String[] args) {
    User userdata = getUser().filter(user1 -> user1.getAge() == 23).orElseGet(User::new);
    System.out.println(userdata);
}

输出:

不符合判断:年龄修改为18

public static Optional<User> getUser(){
    User user = new User(1L, "张三", 18, "1234567", "4234567@qq.com", null);
    return Optional.ofNullable(user);
}
public static void main(String[] args) {
    User userdata = getUser().filter(user1 -> user1.getAge() == 23).orElseGet(User::new);
    System.out.println(userdata);
}

输出结果:

isPresent:判断是否存在数据的判断,存在true,不存在false

public static void main(String[] args) {
    if (getUser().isPresent()) {
        System.out.println("true");
    } else {
        System.out.println("false");
    }
}

public static Optional<User> getUser() {
    User user = new User(1L, "张三", 23, "1234567", "4234567@qq.com", null);
    return Optional.ofNullable(user);
}

map方法:数据转换,转换后的数据也是使用Optiinal包装好的 。

public static Optional<User> getUser() {
    User user = new User(1L, "张三", 23, "1234567", "4234567@qq.com", null);
    return Optional.ofNullable(user);
}
Optional<Long> aLong = getUser().map(user1 -> user1.getUserId());

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值