Java集合基础知识

Java的集合有关知识:


Java集合框架提供了一套性能优良,使用方便的接口和类,主要包括两种类型的容器:集合(Collection) 图(Map)集合存储一个元素集合图存储键/值对映射Collection 接口有三种子类型:ListSetQueue ,而Map 接口下包含了如HashMapTreeMap等具体实现类。

集合和数组的区别

集合与数组都可以存储引用数据类型的对象,但集合提供了更多的数据操作方法,并且可以动态扩展容量。数组在初始化后长度固定,而集合长度可变,更加灵活。

Collection接口的方法(单列集合)


Collection接口是 List *、SetQueue接口的父接口,定义了一些通用的方法*,如

add(e), 添加一个元素

remove(e),删除一个元素

clear(),清空所有元素

contains(object obj),判断是否包含当前元素

isEmpty(),判断是否为空

size(),获取该集合的元素个数

toArray(),把集合的元素转存储到数组中

用于操作集合数据。

集合的遍历:

1、iterator遍历迭代器

2、增强for循环

3、通过lambda表达式进行遍历

java 复制代码
public static void main(String[] args) {
        Collection<String> list = new ArrayList<String>();
        list.add("hello");
        list.add("world");
        list.add("java");

        //TODO:进行遍历
        // 通过遍历迭代器iterator
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            System.out.println(s);
        }

        //TODO: 通过增强for进行遍历
        for (String s : list) {
            System.out.println(s);
        }

        //TODO: 通过lambda表达式进行遍历
        // lambda的原型(函数式接口Consumer泛型的类型和集合的泛型类型一样)
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        list.forEach(s -> System.out.println(s));
    }

在进行集合遍历的修改并发异常问题:

1、通过i--的方法解决

2、通过迭代器的形式进行解决

java 复制代码
public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    list.add("人字拖");
    list.add("老九门");
    list.add("枸杞子");
    list.add("Java");
    list.add("好枸杞");
    list.add("黑枸杞");
    list.add("枸和杞子");
    System.out.println(list);

//     TODO:并发修改异常
    for (int i = 0; i < list.size(); i++) {
        if (list.get(i).contains("枸杞")) {
            list.remove(i);
            i--;
        }
    }
    System.out.println(list);
// TODO:通过迭代器的形式进行遍历修改异常处理
Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String s = iterator.next();
            if (s.contains("枸杞")) {
                iterator.remove();
            }
        }
        System.out.println(list);
}

TreeSet不能对于自定义对象进行排序:

解决方式:

1、需要实现Comparable接口重写其对应的compareTo方法

java 复制代码
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

public class Student implements Comparable<Student> {
    private String name;
    private int age;
    private int score;
    private String sex;

    @Override
    public int compareTo(Student o) {
        return o.getScore()-this.getScore();//降序
        //return this.getScore()-o.getScore();//升序
    }
}

2、在创建TreeSet对象的时候

java 复制代码
new TreeSet<Student>(new Comparator<Student>() {
    @Override
    public int compare(Student o1, Student o2) {
       return o1.getScore()-o2.getScore();//升序
      //return o2.getScore()-o1.getScore();//降序
    }
});

List和Set的区别

  • List:有序集合,可以包含重复元素( 可重复 ),可以通过索引访问元素(有索引有序是指对应的存入顺序是有序的

  • ArrayList:底层基于数组的思想---》查询数据快(可以扩容)

    第一次在添加数据的时候所创建的默认长度为10

  • LinkedList:底层是通过链表的形式----》增删数据快

  • Set无序集合,不允许有重复元素( 不重复 ),主要实现类有HashSetLinkedHashSetTreeSet

  • HashSet:无序,不重复,无索引

    第一次在添加数据的时候所创建的默认长度为16

  • LinkedHashSet:有序,不重复,无索引(有序是存入顺序有序)

  • TreeSet:按照值的大小默认升序排序,不重复,无索引


HashSet对于对象的泛型进行去重

方法:通过重写对象的equals方法和hashCode方法(通过右键直接生成)

java 复制代码
//TODO:重写equals方法,重写hashCode方法

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Student student = (Student) o;
    return age == student.age && score == student.score && Objects.equals(name, student.name) && Objects.equals(sex, student.sex);
}

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

Map接口(双列集合)键值对集合

Map系列的集合的特点都是由键决定的

Map 提供键到值的映射,每个键最多只能映射到一个值

键名不能重复,值可以重复

主要实现类包括HashMapTreeMap----》(不重复是针对于键是否重复,对应的值是可以重复的)

键值对的遍历:

1、获取所有的键返回为一个Set集合,遍历Set,通过键获取值

2、遍历Map集合的另外一种方式:Map调用entrySet方法转为一个Set对象进行遍历

3、通过foreach进行遍历
java 复制代码
public static void main(String[] args) {
//     TODO: 对于Map键值对的遍历
    Map<String, Integer> hashMap = new HashMap<>();
    hashMap.put("张三", 18);
    hashMap.put("李四",32);
    hashMap.put("王五", 20);
    hashMap.put("赵六", 21);

    // 1. 获取所有的键返回为一个Set集合
    Set<String> keys = hashMap.keySet();
    // 2、遍历Set集合
    for (String key : keys) {
        // 3、通过键获取值
        Integer value = hashMap.get(key);
        System.out.println(key + "=" + value);
    }

// TODO: 遍历Map集合的另外一种方式:Map调用entrySet方法
        Set<Map.Entry<String, Integer>> entries = hashMap.entrySet();
        for (Map.Entry<String, Integer> entry : entries){
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + "=" + value);
        }

}
java 复制代码
// TODO: 遍历Map集合的另外一种方式:通过foreach进行遍历
hashMap.forEach(new BiConsumer<String, Integer>() {
    @Override
    public void accept(String key, Integer value) {
        System.out.println(key + "=" + value);
    }
});

//简写
hashMap.forEach((key,value)-> System.out.println(key + "=" + value));

HashMap允许存储一个null键和多个null值-》(无序,不重复,无索引)

TreeMap则按照比较器(Comparator)或自然排序(Comparable)对键进行排序。-》(按照默认大小排序,不重复,无索引)


线程安全和非线程安全的探究

集合类按线程安全性可分为线程安全和非线程安全两类。例如,Vector和Hashtable是线程安全的,而ArrayList和HashMap是非线程安全的

集合的数据结构

  • ArrayXxx:底层数据结构是数组,查询快,增删慢。
  • LinkedXxx:底层数据结构是链表,查询慢,增删快。
  • HashXxx :底层数据结构是哈希表,依赖*hashCode()equals()*方法。
  • TreeXxx:底层数据结构是二叉树,元素有序。

集合的选择

选择使用哪种集合类,取决于具体的应用场景。例如,当需要频繁读取数据时,应选择ArrayList ;当需要频繁插入或删除数据时,应选择LinkedList ;当需要元素唯一且无序时,应选择HashSet ;当需要排序时,应选择TreeSet



Stream流


通过集合对象的stream()方法获取集合对应的Stream流

java 复制代码
public static void main(String[] args) {
//     TODO:集合怎么获取对应的Stream流

    // Collection取对应的Stream流
    Collection<String> list = new ArrayList<>();
    list.stream();

    // Map取对应的Stream流
    //通过键或值获取对应的Stream流
    Map<String, Integer> hashMap = new HashMap<>();
    // 获取对应的键的Stream流
    hashMap.keySet().stream();
    // 获取对应的值的Stream流
    hashMap.values().stream();

    //TODO:数组怎么获得对应的Stream流
    String[] arr = new String[]{"张三","李四","王五"};
    Stream<String> stream = Stream.of(arr);
    //通过Arrays类获取stream流
    Stream<String> stream1 = Arrays.stream(arr);
}

常用方法:

1.forEach(终结方法)

用于遍历的方法,参数传入一个函数式接口:Consumer

java 复制代码
public static void main(String[] args) {
	Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");
	stream.forEach(name‐> System.out.println(name));
}
2.过滤:filter

可以用于过滤

可以通过 filter 方法将一个流转换成另一个子集流。

java 复制代码
public static void main(String[] args) {

        //创建一个流
        Stream<String> stream = Stream.of("张三丰", "刘德华", "张国荣", "彭于晏", "纳什", "吴彦祖", "吴绮蓉");

        //对流中元素过滤,只要姓张的人
        Stream<String> stream2 = stream.filter(name -> {
            return name.startsWith("张");
        });
        
        //遍历过滤后的流
        stream2.forEach(name -> System.out.println(name));
    }
3、统计个数:count(终结方法)

正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数

4、查找最大最小值(终结方法)

max(comparator c)

min(comparator c)

java 复制代码
 /**
     * 查找最大最小值
     */
    @Test
    public void test5(){
        List<Person> list = new ArrayList<>();
        list.add(new Person("马化腾",25,3000));
        list.add(new Person("李彦宏",27,2545));
        list.add(new Person("雷军",35,4515));
        list.add(new Person("马云",55,9877));

        //  查找年龄最大的人
        Optional<Person> max = list.stream().max((e1, e2) -> e1.getAge() - e2.getAge());
        // 返回马云,55岁年龄最大
        System.out.println(max.get());

        System.out.println("--------");

5、收集(终结方法)

collect(Collector c):将流转化为其他形式,接收一个Collector接口的实现

java 复制代码
/**
     * 收集的练习
     */
    @Test
    public void test7(){
        List<Person> list = new ArrayList<>();
        list.add(new Person("马化腾",25,3000));
        list.add(new Person("李彦宏",27,2545));
        list.add(new Person("雷军",35,4515));
        list.add(new Person("马云",55,9877));
        // 把年龄大于30岁的人,转成一个list集合
        List<Person> collect = list.stream().filter(person -> person.getAge() > 30).collect(Collectors.toList());
        // 遍历输出(输出雷军和马云)
        for (Person person : collect) {
            System.out.println(person);
        }

        System.out.println("----------");

        List<Person> list2 = new ArrayList<>();
        list2.add(new Person("马化腾",25,3000));
        list2.add(new Person("李彦宏",27,2545));
        list2.add(new Person("雷军",35,4515));
        list2.add(new Person("马云",55,9877));
        // 把姓马的人,转成Set集合
        Set<Person> set = list2.stream().filter(person -> person.getName().startsWith("马")).collect(Collectors.toSet());
        // 输出马云和马化腾
        set.forEach(System.out::println);

    }
相关推荐
日暮南城故里1 小时前
Java学习------初识JVM体系结构
java·jvm·学习
鱼樱前端1 小时前
Java Jdbc相关知识点汇总
java·后端
canonical_entropy2 小时前
NopReport示例-动态Sheet和动态列
java·后端·excel
kkk哥2 小时前
基于springboot的母婴商城系统(018)
java·spring boot·后端
王者鳜錸2 小时前
四、小白学JAVA-石头剪刀布游戏
java·开发语言·游戏
坚持学习永不言弃3 小时前
【IDEA】 配置安装 Leetcode 插件
java·leetcode·intellij-idea
可乐加.糖5 小时前
Java 分布式高并发重试方案及实现
java·开发语言·spring boot·redis·分布式
沉默的煎蛋5 小时前
深入理解 TCP 三次握手与四次挥手
java·网络·数据结构·网络协议·tcp/ip
猿来入此小猿5 小时前
基于SpringBoot+Vue3实现的宠物领养管理平台功能七
java·spring boot·毕业设计·宠物·宠物领养·毕业源码·免费学习