【Java SE】10.Java集合Stream流&方法引用

📘博客主页:程序员葵安

💻︎素材来源:黑马程序员JAVA课堂

🫶感谢大家点赞👍🏻收藏⭐评论✍🏻

 

                文章目录

一、不可变集合

1.1 不可变集合概念

1.2 不可变集合应用场景

 二、Stream流

2.1 Stream流思想

2.2 Stream流作用 

2.3 Stream流使用步骤

2.4 步骤1获取Stream流

2.5 步骤2使用中间方法

2.6 步骤3使用终结方法 

 三、方法引用

3.1 方法引用概述

3.2 方法引用要求

3.3 方法引用分类


 

一、不可变集合

1.1 不可变集合概念

长度不可变,内容也无法修改的集合

1.2 不可变集合应用场景

  • 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。
  • 当集合对象被不可信的库调用时,不可变形式是安全的。
  • 简单理解:不想让别人修改集合中的内容

1.3 创建不可变集合的书写格式

方法名称

说明

static<E> List<E> of(E...elements)

创建一个具有指定元素的List集合对象

static<E> Set<E> of(E...elements)创建一个具有指定元素的Set集合对象
static<K, V> Map<K, V> of(E...elements)创建一个具有指定元素Map集合对象

代码示例:

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        /*
            创建不可变的List集合
            "张三","李四","王五","赵六"
        */
        System.out.println("创建不可变的List集合");
        //一旦创建,无法修改,只能查询
        List<String> list = List.of("张三","李四","王五","赵六");
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("------------------");
        /*
            创建不可变的Set集合
            "张三","李四","王五","赵六"

            细节:参数要唯一
         */
        System.out.println("创建不可变的Set集合");
        Set<String> set = Set.of("张三","李四","王五","赵六");
        for (String s : set) {
            System.out.println(s);
        }
        System.out.println("------------------");
        /*
            创建不可变的Map集合
            "河北省","石家庄"
            "山西省","太原"
            "辽宁省","沈阳"
            "黑龙江省","哈尔滨"

            细节:键是不能重复的;Map里的of方法参数有上限,最多传递20个参数,10个键值对;
                 如果超过10个键值对,使用Map.ofEntries方法(难记)或Map.copyOf方法(推荐)
         */
        System.out.println("创建不可变的Map集合");
        Map<String,String> map = Map.of(
                "河北省","石家庄",
                "山西省","太原",
                "辽宁省","沈阳",
                "黑龙江省","哈尔滨"
        );
        Set<String> keySet = map.keySet();
        for (String key : keySet) {
            String value = map.get(key);
            System.out.println(key + "=" + value);
        }
        System.out.println("------------------");
    }
}

 二、Stream流

2.1 Stream流思想

2.2 Stream流作用 

结合Lambda表达式,简化集合、数组的操作

2.3 Stream流使用步骤

  1. 先得到一条Stream流(流水线),并把数据放上去
  2. 使用中间方法对流水线上的数据进行操作
  3. 使用终结方法对流水线上的数据进行操作

2.4 步骤1获取Stream流

获取方式

方法名

说明

单列集合

default Stream<E> stream()

Collections中的默认方法

双列集合无法直接使用stream流
数组public static<T> Stream<T> stream(T[] array)Arrays工具类中的静态方法
一堆零散数据public static<T> Stream<T> of(T...values)Stream接口中的静态方法

代码示例: 

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

public class Main {
    public static void main(String[] args) {
        //单列集合获取Stream流
        System.out.println("单列集合获取Stream流");
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a","b","c","d","e");
        //获取流水线,并将集合中的数据放到流水线上
        Stream<String> stream1 = list.stream();
        //使用终结方法打印流水线上的所有数据
        stream1.forEach(s -> System.out.println(s));
        System.out.println("------------------");
        //链式编程简化
        list.stream().forEach(s -> System.out.println(s));
        System.out.println("******************");

        //双列集合获取Stream流
        System.out.println("双列集合获取Stream流");
        HashMap<String,Integer> hm = new HashMap<>();
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);
        hm.put("ddd",444);
        //第一种获取stream流
        hm.keySet().stream().forEach(s -> System.out.println(s));
        System.out.println("------------------");
        //第二种获取stream流
        hm.entrySet().stream().forEach(s -> System.out.println(s));
        System.out.println("******************");

        //数组获取Stream流
        System.out.println("数组获取Stream流");
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        String[] arr2 = {"a","b","c","d","e"};
        //获取stream流
        Arrays.stream(arr).forEach(s -> System.out.println(s));
        System.out.println("------------------");
        Arrays.stream(arr2).forEach(s -> System.out.println(s));
        System.out.println("******************");

        //一堆零散数据获取Stream流
        System.out.println("一堆零散数据获取Stream流");
        Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
        System.out.println("------------------");
        Stream.of("a","b","c","d","e").forEach(s -> System.out.println(s));
    }
}

Stream接口中静态方法of的细节:

  • 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
  • 数组必须是引用数据类型的,如果传递基本数据类型,是把整个数组当作一个元素,放到Stream当中

2.5 步骤2使用中间方法

方法名说明
Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
Stream<T> limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
Stream<T> skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
Stream<T> distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流
Stream<R> map(Function<T, R> mapper)转换流中的数据类型

注意:

  • 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
  • 修改Stream流中的数据,不会影响原来集合或者数组中的数据

 代码示例:

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

public class Main {
    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良","王二麻子","谢广坤");

        //filter 过滤 把张开头的留下,其余数组过滤不要
        System.out.println("filter 过滤");
        list.stream()
                .filter(s -> s.startsWith("张"))
                .forEach(s -> System.out.println(s));
        System.out.println("----------------");

        //limit 截取前几个元素
        System.out.println("limit 截取");
        list.stream()
                .limit(3)
                .forEach(s -> System.out.println(s));
        System.out.println("----------------");

        //skip 跳过前几个元素
        System.out.println("skip 跳过");
        list.stream()
                .skip(3)
                .forEach(s -> System.out.println(s));
        System.out.println("----------------");

        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张无忌","张无忌","张无忌","张强","张三丰","张翠山","张良","王二麻子","谢广坤");

        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"周芷若","赵敏");
        //distinct 去重
        System.out.println("distinct 去重");
        list1.stream()
                .distinct()
                .forEach(s -> System.out.println(s));
        System.out.println("----------------");

        //concat 合并两个流
        System.out.println("concat 合并两个流");
        Stream.concat(list1.stream(),list2.stream())
                .forEach(s -> System.out.println(s));
        System.out.println("----------------");

        //map 转换流中的数据
        System.out.println("map 转换流中的数据");
        ArrayList<String> list3 = new ArrayList<>();
        Collections.addAll(list3,"张无忌-15","周芷若-14","赵敏-13","张强-20","张三丰-100","张翠山-40","张良-35","王二麻子-37","谢广坤-18");
        list3.stream()
                .map(s -> Integer.parseInt(s.split("-")[1]))
                .forEach(s -> System.out.println(s));
    }
}

2.6 步骤3使用终结方法 

方法名说明
void forEach(Consumer action)对此流的每个元素执行操作
long count()返回此流中的元素数
toArray()收集流中的数据,放到数组中
collect(Collector collector)收集流中的数据,放到集合中

代码示例: 

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

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰","张翠山","张良","王二麻子","谢广坤");
        //forEach遍历
        System.out.println("forEach遍历");
        list.stream()
                .forEach(s -> System.out.println(s));
        System.out.println("----------------");

        //count统计
        long count = list.stream().count();
        System.out.println("count统计:"+count);
        System.out.println("----------------");

        //toArray()
        System.out.println("toArray()");
        String[] arr1 = list.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(arr1));
        System.out.println("----------------");

        //collect(Collector collector)
        System.out.println("collect(Collector collector)");
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张无忌-男-15","周芷若-女-14","赵敏-女-13","张强-男-20","张三丰-男-100","张翠山-男-40","张良-男35","王二麻子-男-37","谢广坤-男-41");
        //收集到List集合
        //把所有男性收集起来
        System.out.println("收集到List集合");
        List<String> newList = list1.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toList());
        System.out.println(newList);
        System.out.println("----------------");
        //收集到Set集合
        System.out.println("收集到Set集合");
        Set<String> newSet = list1.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toSet());
        System.out.println(newSet);
        System.out.println("----------------");
        //收集到Map集合
        //键:姓名。值:年龄。
        //键不能重复
        System.out.println("收集到Map集合");
        Map<String,String> newMap = list.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toMap(
                        s -> s.split("-")[0],
                        s -> s.split("-")[2]));
        System.out.println(newMap);
    }
}

 三、方法引用

3.1 方法引用概述

把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体

3.2 方法引用要求

引用处必须是函数式接口

  • 被引用的方法必须已经存在
  • 被引用方法的形参返回值需要跟抽象方法保持一致
  • 被引用方法的功能要满足当前需求

代码示例:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        //需求:创建数组,进行倒序排序
        Integer[] arr = {3,5,4,1,6,2};
        //匿名内部类
        Arrays.sort(arr, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        System.out.println(Arrays.toString(arr));
        //lambda表达式
        Arrays.sort(arr,(Integer o1, Integer o2) -> {
                return o2 - o1;
        });
        System.out.println(Arrays.toString(arr));
        //lambda表达式简化格式
        Arrays.sort(arr,(o1, o2) -> o2 - o1);
        System.out.println(Arrays.toString(arr));
        //方法引用
        Arrays.sort(arr,Main::cmp);
    }

    public static int cmp(int o1, int o2){
        return o2 - o1;
    }
}

 注意:::是方法引用符

3.3 方法引用分类

引用静态方法

格式:

类名::静态方法

Integer::parseInt

代码示例:

import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"1","2","3","4","5");
        list.stream()
                .map(Integer::parseInt)
                .forEach(s -> System.out.println(s));
    }
}

 引用成员方法

格式:

对象1::成员方法

其他类 其他类对象::方法名 

本类     this::方法名

父类     super::方法名

本类和父类引用处不能是静态方法

引用其他类代码示例:

import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌","周芷若","赵敏","张强","张三丰");
        //过滤数据(只要张开头,而且名字是3个字的)
        //常规方法
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length() == 3)
                .forEach(s -> System.out.println(s));
        System.out.println("-----------------------------");
        //其他类
        list.stream()
                .filter(new StringOperation()::stringJudge)
                .forEach(s -> System.out.println(s));
        System.out.println("-----------------------------");
        //本类,其他类
        //注意:静态方法没有this,super,所以只能再创建本类的对象
        list.stream()
                .filter(new Main()::stringJudge)
                .forEach(s -> System.out.println(s));
    }
    public boolean stringJudge(String s){
        return s.startsWith("张") && s.length() == 3;
    }
}

引用构造方法

格式:

类名::new

Student::new

代码示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"张无忌,15","周芷若,14","赵敏,13","张强,20","张三丰,100","张翠山,40","张良,35","王二麻子,37");
        //封装成Student对象并收集到List集合中
        //常规方法
        List<Student> newList1 = list.stream()
                .map(s -> new Student(s.split(",")[0], Integer.parseInt(s.split(",")[1])))
                .collect(Collectors.toList());
        System.out.println(newList1);

        //引用构造方法
        List<Student> newList2 = list.stream()
                .map(Student::new)
                .collect(Collectors.toList());
        System.out.println(newList2);
    }
}

class Student{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String str) {
        String[] arr = str.split(",");
        this.name = arr[0];
        this.age = Integer.parseInt(arr[1]);
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

 其他调用方式

使用类名引用成员方法

格式:

类名::成员方法

String::substring

代码示例:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc","ddd");
        //变成大写后输出
        //常规方法
        list.stream()
                .map(s -> s.toUpperCase())
                .forEach(s -> System.out.println(s));
        System.out.println("---------------------------");
        //使用类名引用成员方法
        list.stream()
                .map(String::toUpperCase)
                .forEach(System.out::println);
    }
}

引用数组的构造方法

格式:

数据类型[]::new

int[]::new

 代码示例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5);
        //将数组收集到数组中
        //常规方法
        Integer[] arr1 = list.stream()
                .toArray(value -> new Integer[value]);
        System.out.println(Arrays.toString(arr1));

        //引用数组的构造方法
        Integer[] arr2 = list.stream()
                .toArray(Integer[]::new);
        System.out.println(Arrays.toString(arr2));
    }
}

小练习:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        ArrayList<Student> list = new ArrayList<>();
        list.add(new Student("zhangsan",23));
        list.add(new Student("lisi",24));
        list.add(new Student("wangwu",25));

        //将姓名放到数组中
        //常规方法
        String[] arr1 = list.stream()
                .map(s -> s.getName())
                .toArray(String[]::new);
        System.out.println(Arrays.toString(arr1));
        //方法引用
        String[] arr2 = list.stream()
                .map(Student::getName)
                .toArray(String[]::new);
        System.out.println(Arrays.toString(arr2));
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值