每日分享之-集合-Map&Stream

1.Collections

1.1可变参数

就是一种特殊形参,定义在方法、构造器的形参列表里

定义格式是:方法名(数据类型...  形参名称){  }

注意:

可变参数在方法内部就是一个数组

一个形参列表中可变参数只能有一个

可变参数必须放在形参列表的最后面

public class Demo {

    public static void main(String[] args) {
        //计算2个整数的和
        add(2,3);
        //计算3个整数的和
        add(3,4,5);
        //计算4个整数的和
        add(4,5,6);
        //计算n个整数的和
        add(4,5,6,7,8,9,10,22);
    }

    public static void add(int...num){
        int sum = 0;
        for (int i : num) {
            sum += i;
        }
        System.out.println(sum);
    }
}

1.2Collections

是一个用来操作集合的工具类

常用方法
    static <T> boolean addAll(单列集合,可变参数)   批量添加元素
    static void shuffle(List集合)    打乱List集合元素顺序,每次调用都会打乱
    static <T> void sort(List集合)   List集合进行自然排序
    static <T> void sort(List集合,比较器)  List集合进行比较器排序
public class Demo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        //static <T> boolean addAll(单列集合,可变参数)   批量添加元素
        Collections.addAll(list, "a", "b", "c", "d", "e");
        System.out.println(list);
        //static void shuffle(List集合)    打乱List集合元素顺序,每次调用都会打乱
        Collections.shuffle(list);
        System.out.println(list);
        //static <T> void  sort(List集合)   List集合进行自然排序
        List<Integer> num = new ArrayList<>();
        Collections.addAll(num, 44,22,11,33,55 );
        Collections.sort(num);
        System.out.println(num);
        //排自定义类对象,需要指定排序规则
        List<Student> stuList = new ArrayList<>();
        stuList.add(new Student("zhangsan", 18));
        stuList.add(new Student("wangwu", 22));
        stuList.add(new Student("zhaoliu", 21));
        stuList.add(new Student("lisi", 19));
        stuList.add(new Student("qianqi", 20));

        //static<T> void sort(List集合,比较器);List集合进行比较器排序
        Collections.sort(stuList, ( o1,  o2)-> o1.getAge() - o2.getAge());
        System.out.println(stuList);
    }
}

2.Map集合

Map集合称为双列集合,一次需要存一对数据做为一个元素, 格式:{key1=value1 , key2=value2 , key3=value3 , ...}

Map集合的每个元素分为两部分:key和value,key称为键,value称为值,整体叫键值对,因此Map也叫“键值对集合

Map集合的所有键是不允许重复的,但值可以重复,键和值是一一对应的,每一个键只能找到自己对应的值

Map应用场景:需要存储一一对应的数据时,就可以考虑使用Map集合来做

2.1Map集合体系

Map集合体系的特点:

Map系列集合的特点都是由键决定的,值只是一个附属品,值是不做要求的

HashMap: 无序、不重复  (用的最多)

LinkedHashMap :有序、不重复

TreeMap: 按照大小默认升序排序、不重复

2.2Map的常用方法

双列集合根接口,它的功能是全部双列集合都可以继承过来使用的。
V put(K key,V value)   添加元素
int size()  获取集合的大小
boolean isEmpty()   判断集合是否为空,为空返回true, 反之
V get(Object key)   根据键获取对应值
V remove(Object key)    根据键删除整个元素
boolean containsKey(Object key)   判断是否包含某个键
boolean containsValue(Object value)   判断是否包含某个值
Set<K> keySet()  获取全部键的集合
Collection<V> values()   获取Map集合的全部值
void clear()    清空集合
public class Demo1 {
    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        //V put(K key,V value)   添加元素
        map.put("001", "张三");
        map.put("002", "李四");
        map.put("003", "王五");
        map.put("004", "赵六");
        System.out.println(map);
        //int size()	获取集合的大小
        System.out.println(map.size()); //4
        //boolean isEmpty()	判断集合是否为空,为空返回true, 反之
        System.out.println(map.isEmpty()); //false
        //V get(Object key)	根据键获取对应值
        String value = map.get("001");
        System.out.println(value);  //张三
        //V remove(Object key)	根据键删除整个元素
        map.remove("001");
        System.out.println(map);
        //boolean containsKey(Object key)	  判断是否包含某个键
        System.out.println(map.containsKey("001"));   //false
        //boolean containsValue(Object value)	  判断是否包含某个值
        System.out.println(map.containsValue("李四"));   //true
        //Set<K> keySet()	 获取全部键的集合
        Set<String> strings = map.keySet();
        System.out.println(strings);   //002,003,004
        //Collection<V> values()	 获取Map集合的全部值
        Collection<String> values = map.values();
        System.out.println(values);   //李四,王五,赵六
        //void clear()	清空集合
        map.clear();
        System.out.println(map);  //{}
    }
}

2.3遍历方式

Map集合的遍历方式一:先获取Map集合全部的键,再通过遍历键来找值

public class Demo2 {
    public static void main(String[] args) {
        //1. 创建map
        Map<String, String> map = new HashMap<>();
        map.put("a", "aaa");
        map.put("b", "bbb");
        map.put("c", "ccc");
        System.out.println(map);
        //2. 各种方式进行遍历
        test1(map);
        test2(map);
        test3(map);
    }

    //遍历方式1: 先获取Map集合全部的键,再通过遍历键来找值
    private static void test1(Map<String, String> map) {
        Set<String> keys = map.keySet();
        for (String key : keys) {
            String string = map.get(key);
            System.out.println(key + "=" + string);
        }

    }

Map集合的遍历方式二:把“键值对”看成一个整体进行遍历

    //遍历方式2: 将map中的所有键值对放入一个set集合中, 然后遍历set集合拿到每个键值对, 再取里面的键值
    private static void test2(Map<String, String> map) {
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "=" + value);
        }

    }

Map集合的遍历方式三 :结合lambda的遍历方法

  //遍历方式3: Lambda, 使用foreach(BiConsumer bc)
    private static void test3(Map<String, String> map) {
        map.forEach((k,v)->System.out.println(k+"="+v));
    }
}

2.4HashMap

HashMap跟HashSet的底层原理是一模一样的,都是基于哈希表实现的。

实际上:Set系列集合的底层就是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据而已。

JDK8之前,哈希表 = 数组+链表

JDK8开始,哈希表 = 数组+链表+红黑树

哈希表是一种增删改查数据,性能都较好的数据结构。

HashMap的键依赖hashCode方法和equals方法保证键的唯一

2.5LinkedHashMap

底层数据结构依然是基于哈希表实现的,只是每个键值对元素又额外的多了一个双链表的机制记录元素顺序(保证有序)。

实际上:原来学习的LinkedHashSet集合的底层原理就是LinkedHashMap。

2.6TreeMap

特点:不重复、无索引、可排序(按照键的大小默认升序排序,只能对键排序)

原理:TreeMap跟TreeSet集合的底层原理是一样的,都是基于红黑树实现的排序。

TreeMap集合同样也支持两种方式来指定排序规则

让类实现Comparable接口,重写比较规则。

TreeMap集合有一个有参数构造器,支持创建Comparator比较器对象,以便用来指定比较规则。

Map集合案例-省和市

要求:

在程序中记住如下省份和其对应的城市信息,记录成功后,要求可以查询出湖北省的城市信息。

public class Demo7 {
    public static void main(String[] args) {
        Map<String, ArrayList> map = new HashMap<>();
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"南京市","扬州市","苏州市","无锡市","常州市");
        map.put("江苏省",list1);
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"武汉市","孝感市","十堰市","宜昌市","鄂州市");
        map.put("湖北省",list2);
        ArrayList<String> list3 = new ArrayList<>();
        Collections.addAll(list3,"石家庄市","唐山市","邢台市","保定市","张家口市");
        map.put("河北省",list3);

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你要查询的城市:");
        String city = sc.next();
        Set<Map.Entry<String, ArrayList>> entries = map.entrySet();
        for (Map.Entry<String, ArrayList> entry : entries) {
            if (entry.getKey().equals(city)){
                ArrayList value = entry.getValue();
                System.out.println(value);
                break;
            }else {

            }
        }



    }
}

3.Stream

Stream也叫Stream流,是Jdk8开始新增的一套API ,可以用于操作集合或者数组的数据。

优势: Stream流大量的结合了Lambda的语法风格来编程,提供了一种更加强大,更加简单的方式

操作集合或者数组中的数据,代码更简洁,可读性更好。

3.1Stream的使用步骤

1. 先得到集合或者数组的Stream流(获取)

2.调用Stream流的方法对数据进行处理(操作)

3.获取处理的结果(终结)

3.2Stream的常用的方法

中间方法
    对stream流进行操作的方法, 他们调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。
常见的中间方法
    Stream<T> filter(Predicate<? super T> p) 按照规则过滤,保留满足条件的元素
    Stream<T> sorted() 升序排序
    Stream<T> sorted(Comparator<? super T> c) 按照规则排序
    Stream<T> limit(long maxSize) 截取
    Stream<T> skip(long n)  跳过
    Stream<R> map(Function<? super T, extends R> mapper) 对元素进行加工,并返回对应的新流
    Stream<T> distinct() 去重
    static <T> Stream<T> concat(Stream a,Stream b) 合并流
public class Demo3 {
    public static void main(String[] args) {
        List<Integer> list = List.of(61, 57, 66, 77, 88, 44, 100, 89, 97, 47, 70);
        //需求1: 找出所有及格的分数,并打印
        System.out.println("=================");
        list.stream()
                .filter(e -> e >= 60)
                .forEach(System.out::println);
        //需求2: 找出所有及格的分数, 正序排列, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e > 60)
                .sorted()
                .forEach(System.out::println);
        //需求3: 找出所有及格的分数, 倒序排列, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e > 60)
                .sorted((o1, o2) -> o2 - o1)
                .forEach(System.out::println);

        //需求4: 找出所有及格的分数, 倒序排列, 取前3名, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e > 60)
                .sorted((o1, o2) -> o2 - o1)
                .limit(3)
                .forEach(System.out::println);

        //需求5: 找出所有及格的分数, 倒序排列, 取前4-6名, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e > 60)
                .sorted((o1, o2) -> o2 - o1)
                .skip(3)
                .limit(3)
                .forEach(System.out::println);

        //需求6:  找出所有及格的分数, 倒序排列, 取前4-6名, 将每个人的分数加10分, 打印输出
        System.out.println("=================");
        list.stream()
                .filter(e -> e > 60)
                .sorted((o1, o2) -> o2 - o1)
                .skip(3)
                .limit(3)
                .map(e->e + 10)
                .forEach(System.out::println);
    }
}

终结方法1
    调用完成后,不会返回新Stream了,没法继续使用流了。
    它的作用是对流中的数据进行筛选(遍历、最大、最小、统计个数)
    
常用方法
    void forEach(Consumer consumer)  遍历流中的数据
    long count() 统计流中元素的个数
    Optional max(Comparator<? super T> comparator) 获取流中的最大值
    Optional min(Comparator<?super T> comparator) 获取流中的最小值
public class Demo4 {
    public static void main(String[] args) {
        List<Student> list = List.of(
                new Student("玄奘", 60, 165.5),
                new Student("悟空", 50, 175.5),
                new Student("悟能", 55, 145.5),
                new Student("悟净", 40, 185.5)
        );

        //1. 打印出集合中所有元素
        list.stream()
                .forEach(e ->System.out.println(e));
        //2. 统计出身高不足170的人数
        long count = list.stream()
                .filter(e -> e.getHeight() < 170)
                .count();
        System.out.println(count);
        //3. 请找出年龄最大的对象, 并输出(了解)
        Optional<Student> max = list.stream()
                .max((o1, o2) -> o1.getAge() > o2.getAge() ? 1 : -1);
        System.out.println("年龄最大的对象:"+max);
        //4. 请找出身高最高的对象, 并输出(了解)
        Optional<Student> max1 = list.stream()
                .max((o1, o2) -> o1.getHeight() > o2.getHeight() ? 1 : -1);
        System.out.println("身高最高的对象:"+max1);

    }
}

class Student {
    private String name;
    private int age;
    private double height;

    public Student() {
    }

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

    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 getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

终结方法2
    调用完成后,不会返回新Stream了,没法继续使用流了。
    它的作用是用来收集Stream流的结果转回到集合或者数组中去返回。

常见方法
    R collect(Collector collector); 将流中数据收集到指定集合,参数传递Collectors工具类调用对应方法
        Collectors.toList()
        Collectors.toSet()
        Collectors.toMap()
        Object[] toArray();
public class Demo5 {
    public static void main(String[] args) {
        List<Teacher> list = List.of(
                new Teacher("玄奘", 60, 165.5),
                new Teacher("悟空", 50, 175.5),
                new Teacher("悟空", 50, 175.5),
                new Teacher("悟能", 55, 145.5),
                new Teacher("悟净", 40, 185.5));

        //1. 请找出身高超过170的教师, 并放到一个新数组中
        Object[] array = list.stream()
                .filter(e -> e.getHeight() > 170)
                .toArray();
        System.out.println(Arrays.toString(array));
        //2. 请找出身高超过170的教师, 并放到一个新List集合中
        List<Teacher> list1 = list.stream()
                .filter(e -> e.getHeight() > 170)
                .collect(Collectors.toList());
        System.out.println(list1);

        //3. 请找出身高超过170的教师, 并放到一个新Set集合中
        Set<Teacher> collect = list.stream()
                .filter(e -> e.getHeight() > 170)
                .collect(Collectors.toSet());
        System.out.println(collect);

        //4. 请找出所有的教师的姓名和身高, 放到一个新Map集合中
        Map<Object, Object> collect1 = list.stream().distinct()
                .collect(Collectors.toMap((Teacher teacher) -> teacher.getName(),
                        (Teacher teacher) -> teacher.getHeight()));
        System.out.println(collect1);
    }
}

class Teacher {
    private String name;
    private int age;
    private double height;

    public Teacher() {
    }

    public Teacher(String name, int age, double height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    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 getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Teacher teacher = (Teacher) o;
        return age == teacher.age && Double.compare(teacher.height, height) == 0 && Objects.equals(name, teacher.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, height);
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                '}';
    }
}

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值