1.Stream流
- Stream 流是 Java 8 引入的函数式编程核心特性,用于对集合(或数组)进行高效、声明式的操作(过滤、映射、聚合等)。它的设计目标是简化集合处理代码,同时支持并行处理以提升性能。
  
核心特点
- 不存储数据:Stream 只是操作数据的 "管道",不会修改原始集合。
- 一次性使用:一个 Stream 只能遍历一次,再次使用需重新创建。
- 延迟执行:中间操作(如过滤、映射)不会立即执行,直到终端操作(如收集、打印)触发时才会执行,类似 "惰性求值"。
- 支持并行:可通过 parallelStream() 轻松实现并行处理,适合大数据量场景。
代码案例
            
            
              java
              
              
            
          
          public class StreamExample {
    public static void main(String[] args) {
        // 假设存在一个存储姓名的原始集合
        List<String> nameList = List.of("张三", "李四", "张三丰", "张伟", "张晓明", "王五");
        // 1. 传统方式:找出姓张且名字为3个字的人,存入新集合
        // 创建新集合用于存储结果
        List<String> newList = new ArrayList<>();
        // 遍历原始集合中的每个姓名
        for (String name : nameList) {
            // 过滤条件:姓名以"张"开头 并且 长度为3
            if (name.startsWith("张") && name.length() == 3) {
                // 符合条件的姓名添加到新集合
                newList.add(name);
            }
        }
        // 打印传统方式的结果
        System.out.println("传统方式筛选结果:" + newList);
        // 2. 使用Stream流解决相同问题
        将每一个对象nameObj进行类似于EXCEL的层层筛选
        // 步骤解析:
        // a. nameList.stream():将集合转换为Stream流,开启流操作
        // b. filter(s -> s.startsWith("张")):第一个过滤中间操作,保留以"张"开头的姓名
        // c. filter(s -> s.length() == 3):第二个过滤中间操作,保留长度为3的姓名
        // d. collect(Collectors.toList()):终端操作,将流处理结果收集为List集合
        List<String> newList2 = nameList.stream()
                .filter(nameObj-> nameObj.startsWith("张"))  // 过滤条件1:姓张
                .filter(nameObj-> nameObj.length() == 3)     // 过滤条件2:名字3个字
                .collect(Collectors.toList());          // 收集结果为新集合
        // 打印Stream流方式的结果
        System.out.println("Stream流筛选结果:" + newList2);
    }
}2.Stream流-中间方法

案例2
            
            
              java
              
              
            
          
          public class StreamDemo {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("apple", "banana", "orange", "grape", "watermelon", "pear");
        // 1. 过滤(filter):保留长度>5的单词
        List<String> longWords = words.stream()
                .filter(word -> word.length() > 5) // 中间操作:过滤
                .collect(Collectors.toList()); // 终端操作:收集为List
        System.out.println("长度>5的单词:" + longWords); // [banana, orange, watermelon]
        // 2. 映射(map):将单词转为大写
        List<String> upperWords = words.stream()
                .map(String::toUpperCase) // 中间操作:映射(方法引用简化)
                .collect(Collectors.toList());
        System.out.println("大写单词:" + upperWords); // [APPLE, BANANA, ORANGE, GRAPE, WATERMELON, PEAR]
        // 3. 排序(sorted):按长度升序排列
        List<String> sortedWords = words.stream()
                .sorted((s1, s2) -> s1.length() - s2.length()) // 中间操作:排序
                .collect(Collectors.toList());
        System.out.println("按长度排序:" + sortedWords); // [pear, apple, grape, banana, orange, watermelon]
        // 4. 聚合(count):统计长度<=5的单词数量 聚合还有很多,问AI
        long shortWordCount = words.stream()
                .filter(word -> word.length() <= 5)
                .count(); // 终端操作:计数
        System.out.println("长度<=5的单词数量:" + shortWordCount); // 3(apple、grape、pear)
        // 5. 遍历(forEach):打印所有单词
        System.out.print("所有单词:");
        words.stream()
                .forEach(word -> System.out.print(word + " ")); // 终端操作:遍历
        // 输出:所有单词:apple banana orange grape watermelon pear 
    }
}案例3
            
            
              java
              
              
            
          
          // 学生类
class Student {
    private String id;
    private String name;
    private int age;
    public Student(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    // getter方法(Stream操作需要)
    public String getId() { return id; }
    public String getName() { return name; }
    public int getAge() { return age; }
    @Override
    public String toString() {
        return "Student{id='" + id + "', name='" + name + "', age=" + age + "}";
    }
}
public class MapStreamDemo {
    public static void main(String[] args) {
        // 初始化一个Map:键为学生ID,值为Student对象
        Map<String, Student> studentMap = new HashMap<>();
        studentMap.put("001", new Student("001", "张三", 17));
        studentMap.put("002", new Student("002", "李四", 19));
        studentMap.put("003", new Student("003", "王五", 20));
        studentMap.put("004", new Student("004", "赵六", 18));
        studentMap.put("005", new Student("005", "孙七", 17));
        // 1. 从entrySet()获取流(推荐,同时操作键和值)
        System.out.println("=== 1. 过滤年龄≥18的学生,保留ID和姓名 ===");
        Map<String, String> adultNameMap = studentMap.entrySet().stream()
                // 过滤:年龄≥18
                .filter(entry -> entry.getValue().getAge() >= 18)
                // 映射:键保留ID,值转换为姓名(大写)
                .collect(Collectors.toMap(
                        Map.Entry::getKey,  // 新键:原键(学生ID)
                        entry -> entry.getValue().getName().toUpperCase()  // 新值:姓名大写
                ));
        adultNameMap.forEach((k, v) -> System.out.println(k + " -> " + v));
        // 2. 从values()获取流(仅操作值)
        System.out.println("\n=== 2. 提取所有学生的年龄,求平均值 ===");
        OptionalDouble ageAvg = studentMap.values().stream()
                // 映射为年龄的IntStream
                .mapToInt(Student::getAge)
                // 求平均值
                .average();
        ageAvg.ifPresent(avg -> System.out.println("平均年龄:" + avg));
        // 3. 从keySet()获取流(通过键查值,效率较低,不推荐)
        System.out.println("\n=== 3. 筛选ID以'00'开头的学生 ===");
        List<Student> filteredStudents = studentMap.keySet().stream()
                // 过滤:ID以"00"开头
                .filter(id -> id.startsWith("00"))
                // 通过键获取值(学生对象)
                .map(studentMap::get)
                // 收集为List
                .collect(Collectors.toList());
        filteredStudents.forEach(System.out::println);
        // 4. 分组聚合:按年龄分组,统计每个年龄段的学生数量
        System.out.println("\n=== 4. 按年龄分组统计人数 ===");
        Map<Integer, Long> ageCountMap = studentMap.values().stream()
                // 按年龄分组,值为每个组的人数(计数)
                .collect(Collectors.groupingBy(
                        Student::getAge,  // 分组依据:年龄
                        Collectors.counting()  // 统计每组数量
                ));
        ageCountMap.forEach((age, count) -> System.out.println("年龄" + age + ":" + count + "人"));
      
        // 5.合并流
		Stream<String> s1 = Stream.of("张三丰", "张无忌", "张翠山", "张角", "张学良");
		Stream<Integer> s2 = Stream.of(111, 22, 33, 44);
		Stream<Object> s3 = Stream.concat(s1, s2);
		System.out.println(s3.count());
    }
}2.Stream流-终结方法

3.可变参数
- 可变参数(varargs)允许方法接收数量不固定的同类型参数,语法为 类型... 参数名,本质是数组的简化写法。以下是常用案例:
            
            
              java
              
              
            
          
          public class CollectionUtil {
    // 向集合中添加任意数量的元素
    public static <T> void addAll(List<T> list, T... elements) {
        for (T elem : elements) {
            list.add(elem);
        }
    }
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        addAll(fruits, "苹果", "香蕉", "橙子"); // 批量添加3个元素
        System.out.println(fruits); // 输出:[苹果, 香蕉, 橙子]
    }
}核心注意点
- 语法规则:可变参数必须写成 类型... 参数名,且必须是方法的最后一个参数(避免歧义)。
- 本质是数组:方法内部可将可变参数当作数组处理(如 numbers.length、for 循环遍历)。
- 参数兼容:调用时可传入单个元素、多个元素或数组,编译器会自动封装为数组。
- 避免重载陷阱:若方法重载时包含可变参数,可能导致调用歧义(如 method(int... a) 和 method(int a, int... b) 需谨慎使用)。
- 可变参数适用于参数数量不确定但类型一致的场景,能简化代码,避免重载多个参数个数不同的方法。