Stream编程

JDK8新增,容器对象功能的增强,我们可以将流看作流水线,这个流水线是处理数据的流水线

当我们使用一个流的时候,通常包括三个步骤

  1. 获取一个数据源
  2. 执行操作获取想要的结果
  3. 每次操作,原有的流对象不改变,返回一个新的Stream对象

Stream有几个特性

  1. Stream不存储数据,一般会输出结果
  2. Stream不会改变数据源,通常情况下会生成一个新的集合
  3. Stream具有延迟执行的特性,只有调用终端操作时,中间操作才会执行

基础运用

@Test
public void test01() {
    List<String> list = Arrays.asList("a","b","c");
    // 创建一个顺序流
    Stream<String> stream = list.stream();
    // 创建一个并行流
    Stream<String> parallelStream = list.parallelStream();

    Stream<Integer> stream1 = Stream.of(1, 2, 3, 4, 5, 6);

    Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
}

一些方法运用

代码

import org.junit.Before;
import org.junit.Test;

import java.lang.invoke.VarHandle;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Ch06 {

    // 创建一个复杂的集合
    List<Person> personList = new ArrayList<>();
    // 创建一个简单的集合
    List<Integer> simpleList = Arrays.asList(15,22,15,11,33,52,22,14,33,52);

    @Before
    public void before() {
        personList.add(new Person("张三",3000,23,"男","长春"));
        personList.add(new Person("李四",7000,34,"男","西安"));
        personList.add(new Person("王五",5000,22,"女","长春"));
        personList.add(new Person("小明",1000,33,"女","上海"));
        personList.add(new Person("小红",8000,44,"女","北京"));
        personList.add(new Person("小黑",6000,36,"女","南京"));
    }

    @Test
    public void test01(){
        // 打印集合元素
        // 双冒号语法,方法引用
        simpleList.stream().forEach(System.out::println);
        // 其实还可以简化操作
        simpleList.forEach(System.out::println);
    }

    @Test
    public void test02() {
        // 找到第一个元素
        Optional<Integer> first = simpleList.stream().findFirst();

        // 随便找一个
        // 如果没有并行,any也是第一个
        Optional<Integer> any = simpleList.stream().findAny();

        System.out.println("第一个:" + first.get());
        System.out.println("任意一个:" + any.get());
    }

    @Test
    public void test03() {
        // 判断有没有任意一个人年龄大于35岁
        // 任意匹配
        boolean b = personList.stream()
                .anyMatch(item -> item.getAge() > 35);
        System.out.println(b);

        // 判断是不是所有人年龄都大于35岁
        b = personList.stream().allMatch(item -> item.getAge() > 35);
        System.out.println(b);
    }

    @Test
    public void Ch07() {

        List<Integer> collect = simpleList.stream().collect(Collectors.toList());
        System.out.println(collect);
        Set<Integer> collect1 = simpleList.stream().collect(Collectors.toSet());
        System.out.println(collect1);
        Map<Integer, Integer> map = simpleList.stream()
                .collect(Collectors
                        .toMap(item -> item, item -> item + 1));
        System.out.println(map);
    }

    @Test
    public void Ch08() {
        // 统计
        long count = new Random().ints().limit(50).count();
        System.out.println(count);
        OptionalDouble average = new Random().ints().limit(50).average();
        average.ifPresent(System.out::println);
        int sum = new Random().ints().limit(50).sum();
        System.out.println(sum);
    }

    /*
        归约(reduce)缩减,把一个流缩减成一个值,
        可以实现对集合的求和,求乘积,求最值
     */
    @Test
    public void test09(){
        Integer result = simpleList.stream().reduce(1, (n1, n2) -> n1 - n2);
        System.out.println(result);
    }

    @Test
    public void test10(){
        List<String> list = Arrays.asList("A","B","C");
        String string = list.stream().collect(Collectors.joining("-"));
        System.out.println("拼接后的字符串:" + string);
    }

    /*
        分组将集合分为多个map,
        比如员工按性别分组
        员工按薪资是否高于8000分组
     */
    @Test
    public void test11() {
        // 根据工资分组
        Map<Boolean, List<Person>> collect = personList.stream().collect(Collectors.groupingBy(x -> x.getSalary() > 5000));
        System.out.println(collect);
        // 根据性别分组
        Map<String, List<Person>> collect1 = personList.stream().collect(Collectors.groupingBy(Person::getGender));
        System.out.println(collect1);

        // 将员工根据性别分组,再按地区分组
        Map<String, Map<String, List<Person>>> collect2 = personList.stream()
                .collect(Collectors.groupingBy(Person::getGender, Collectors.groupingBy(Person::getArea)));
        System.out.println(collect2);
    }

    /**
     * 筛选
     */
    @Test
    public void test12() {
//        simpleList.stream().filter(item -> item > 17).forEach(System.out::println);

        // 筛选员工中工资大于8000的人,并形成新的集合
        List<Person> collect = personList
                .stream()
                .filter(item -> item.getSalary() > 5000)
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 映射
     * 将一个流的元素按照一定的映射规则映射到另一个流中。
     */
    @Test
    public void test13(){
        // 将员工的工资全部增加1000
//        personList
//                .stream().map(item -> {
//            item.setSalary(item.getSalary() + 1000);
//            return item;
//        }).forEach(System.out::println);
        List<StringBuilder> collect = simpleList.stream().map(item -> {
            StringBuilder strb = new StringBuilder();
            strb.append(item);
            return strb;
        }).collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 排序:sorted
     * 自然排序:
     * 临时排序:
     */
    @Test
    public void test14() {
        // 将员工按工资由低到高排序(自然排序--升序)
        List<String> collect = personList.stream()
                .sorted(Comparator.comparing(Person::getSalary))
                .map(Person::getName)
                .collect(Collectors.toList());
        System.out.println(collect);
        // 按照员工工资的降序
        List<String> collect1 = personList
                .stream()
                .sorted(Comparator.comparing(Person::getSalary).reversed())
                .map(Person::getName)
                .collect(Collectors.toList());
        System.out.println(collect1);
    }

    /**
     * peek操作,调试
     */
    @Test
    public void test15(){
        // 在stream中调试,stream不支持debug
        List<Person> collect = personList.stream()
                .filter(item -> item.getSalary() > 5000)
                .peek(System.out::println)
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 其他操作:合并、去重、限制、跳过。。。。
     */
    @Test
    public void test16() {
        /*
            distinct:去重
            skip:跳过几个数据
            limit:限制使用几个数据
         */
        simpleList
                .stream()
                .distinct()
                .skip(2)
                .limit(6)
                .forEach(System.out::println);


    }

}


JDK8函数式接口

  • Consumer:消费者 void accept(T t)
  • Supplier:供应商 T get()
  • Function: R apply(T t),将一个数据转化成另一个数据
  • Predicate:断言,boolean test(T t),判断返回值是boolean
Optional类是java8为了解决null问题
  • JDK8新增:
  • 1.函数式接口
  • 2.箭头函数(lambda表达式),不是java特有的。阉割版
  • 3.Optional类
  • 4.断言
  • 5.Stream编程
public class Ch08 {

    @Test
    public void test01() {
        String str = null;
        // 返回一个对象值为空的Optional对象
//        Optional<String> empty = Optional.empty();
//        Optional<String> hello = Optional.of(str);
        Optional<String> o = Optional.ofNullable(null);
        System.out.println(o.get());
    }
}

制作仿CMD

public class CMD {

    static Scanner scanner = new Scanner(System.in);

    public static String getDocument(String document) {
        if (document.contains(".")) {
            return "文件";
        }
        return "文件夹";
    }
    public static void mainMenu() throws IOException {
        String currentDir = System.getProperty("user.dir");

        cmd:while (true) {

            System.out.print(currentDir+" > ");
            String command = scanner.nextLine();
            String[] commands = command.split(" ");
            String document = "";

            switch (commands[0]) {
                case "mkdir":
                    if (commands.length >=2) {
                        document = getDocument(commands[1]);

                        if (new File(currentDir + "//" +commands[1]).mkdir()) {
                            System.out.println(document+":" + commands[1] + " 已创建!\n");
                        } else {
                            System.out.println(document+":" + commands[1] + " 创建失败,可能已经存在该文件夹!\n");
                        }
                    } else {
                        System.out.println("你可以输入 \"mkdir 名字\" 来创建相应名字的文件夹!");
                    }
                    continue cmd;
                case "rd":
                    if (commands.length >=2) {
                        document = getDocument(commands[1]);

                        if (new File(currentDir + "//" +commands[1]).delete()) {
                            System.out.println(document+":" + commands[1] + " 已删除!\n");
                        } else {
                            System.out.println(document+":" + commands[1] + " 删除失败!\n");
                        }
                    } else {
                        System.out.println("你可以输入 \"rd 名字\" 来删除相应名字的文件夹或文件!");
                    }
                    continue cmd;
                case "cnf":
                    if (commands.length >=2) {
                        document = getDocument(commands[1]);

                        if (new File(currentDir + "//" +commands[1]).createNewFile()) {
                            System.out.println(document+":" + commands[1] + " 已创建!\n");
                        } else {
                            System.out.println(document+":" + commands[1] + " 创建失败!\n");
                        }
                    } else {
                        System.out.println("你可以输入 \"cnf 名字\" 来创建相应名字的文件!");
                    }
                    continue cmd;
                case "dir":
                    String[] newArr = new File(currentDir+ "//").list();
                    if (newArr == null) {
                        System.out.println("当前目录下貌似没有任何文件!");
                    } else {
                        for (String s : newArr) {
                            System.out.println(s);
                        }
                    }
                    continue cmd;
                default:
                    if (commands[0].equals("C:") || commands[0].equals("D:") || commands[0].equals("E:") || commands[0].equals("F:") ) {
                        currentDir = commands[0] + "\\";
                    } else {
                        System.out.println("无效的命令,请重新输入!");
                        continue cmd;
                    }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        mainMenu();
    }
}

停下脚步活在当下,即使总有一天会失去。把放弃的梦想托付给谁不是也很好吗。 ——木藤亚也《一公升眼泪》
最后修改:2023 年 01 月 09 日
如果觉得我的文章对你有用,请随意赞赏