13.集合框架

news/2025/4/2 8:04:48/文章来源:https://www.cnblogs.com/icui4cu/p/18802611

本章目标

  • 集合(理解)
  • List接口之ArrayList(熟练)
  • LinkedList(掌握)
  • Vector(掌握)
  • 集合排序(掌握)

本章内容

一、集合

Java中的集合(collection)和数学上直观的集(set)的概念是相同的。集是一个唯一项组,也就是说组中没有重复项。英国数学家 George Boole 按逻辑正式的定义了集的概念。

大部分人在高中时通过我们熟悉的维恩图引入的集的交和集的并学到过一些集的理论

集内只包含每项的一个实例

集可以是有限的,也可以是无限的

1、为什么用集合

  • 不知道存放对象的个数
  • 与数组相比更加实用灵活
  • 更加面向对象

2、体系结构

架构图

3、Collection接口

Collection 接口用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。Collection 在前面的大图也可以看出,它是List和Set 的父类,并且它本身也是一个接口,它定义了作为集合所应该拥有的一些方法。

  • 集合必须只有对象,集合中的元素不能是基本数据类型。
  • Collection接口支持如添加和除去等基本操作。设法除去一个元素时,如果这个元素存在,除去的仅仅是集合中此元素的一个实例
方法名 描述
add(E e) 确保此 collection 包含指定的元素(可选操作)
clear() 移除此 collection 中的所有元素(可选操作)
contains(Object o) 如果此集合包含指定的元素,则返回 true
isEmpty() 如果此集合不包含元素,则返回 true
iterator() 返回此集合中的元素的迭代器
remove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)
size() 返回此集合中的元素数。
toArray() 返回一个包含此集合中所有元素的数组

3.1、Set 接口

Set 接口继承 Collection,但不允许重复,使用自己内部的一个排列机制

3.2、List 接口

List 接口继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列

3.3、Map接口

Map接口是一组成对的键-值对象,即所持有的是key-value 形式。Map中不能有重复的key。拥有自己的内部排列机制。 关键字决定了对象在映射中的存储位置,检索对象时必须提供相应的关键字,就像在字典中查单词一样

二、List接口

1、概念

java.util.List接口继承自Collection接口,在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素,另外List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致

2、List 的分类

List 可以分为以下几类:

  • ArrayList

ArrayList 是一种基于数组实现的 List,可以动态地增加和缩减数组的大小。ArrayList 支持快速随机访问和插入操作,但是在删除和插入操作时需要移动数组中的元素,所以效率比较低。ArrayList 是线程不安全的,不适用于多线程环境。

  • LinkedList

LinkedList 是一种基于链表实现的 List,可以快速插入和删除元素,但是随机访问元素的效率比较低。LinkedList 是线程不安全的,不适用于多线程环境。

  • Vector

Vector 是一种与 ArrayList 相似的 List,支持快速随机访问和插入操作,并且支持同步操作,适用于多线程环境。Vector 的效率比 ArrayList 低,不推荐在单线程环境中使用

3、ArrayList

ArrayList是List 接口的大小可变数组的实现。允许包括 null 在内的所有元素。每个 ArrayList 实例都有一个容量。该容量是用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向 ArrayList 中不断添加元素,其容量也自动增长

3.1、类结构

QQ20210219-143407@2x

3.2、常用方法

方法 说明
void add(int index, Object element): 在指定位置index上添加元素element
boolean addAll(int index, Collection c): 将集合c的所有元素添加到指定位置index
Object get(int index): 返回List中指定位置的元素
int indexOf(Object o): 返回第一个出现元素o的位置,否则返回-1
int lastIndexOf(Object o) : 返回最后一个出现元素o的位置,否则返回-1
Object remove(int index) 删除指定位置上的元素
Object set(int index, Object element) 用元素element取代位置index上的元素,并且返回旧的元素

3.3、示例

 public class ArrayListDemo {
     public static void main(String[] args) {
         ArrayList arrayList = new ArrayList();
         arrayList.add("one");
         arrayList.add("one");
         arrayList.add("two");
         arrayList.add(3);
         arrayList.add(new Date());
         arrayList.add(null);
         System.out.println("列表的长度=" + arrayList.size());
         System.out.println("列表的内容=" + arrayList);         System.out.println("-------开始循环遍历-------");
         for(int i = 0 ; i < arrayList.size() ; i++ ){
             System.out.println(arrayList.get(i));
         }         System.out.println("-------替换元素-------");
         arrayList.set(5, new Student("周翔",19,"清华"));
         System.out.println("-------替换后循环遍历-------");
         for(int i = 0 ; i < arrayList.size() ; i++ ){
             System.out.println(arrayList.get(i));
         }         System.out.println("-------插入数据-------");
         arrayList.add(1,"被插入的数据");
         System.out.println("--------------插入数据后循环遍历");
         for(int i = 0 ; i < arrayList.size() ; i++ ){
             System.out.println(arrayList.get(i));
         }     }
 
 }

3.4、扩容(扩展)

ArrayList 的扩容机制是在添加元素时判断当前数组大小是否已经满了,如果已经满了,则创建一个新的更大的数组,并将原来的元素全部复制到新的数组中。具体的扩容规则如下:

 /**
      * Increases the capacity to ensure that it can hold at least the
      * number of elements specified by the minimum capacity argument.
      *
      * @param minCapacity the desired minimum capacity
      */
     private void grow(int minCapacity) {
         // overflow-conscious code
         int oldCapacity = elementData.length;
         int newCapacity = oldCapacity + (oldCapacity >> 1);//位右移,相当于oldCapacity/2
         if (newCapacity - minCapacity < 0)
             newCapacity = minCapacity;
         if (newCapacity - MAX_ARRAY_SIZE > 0)
             newCapacity = hugeCapacity(minCapacity);
         // minCapacity is usually close to size, so this is a win:
         elementData = Arrays.copyOf(elementData, newCapacity);
     }
  • 当添加元素后,size 大小已经等于或超过了数组的容量 capacity 时,就会触发扩容操作。
  • 扩容的大小默认情况下为原数组大小的一半。比如原数组大小为 10,那么扩容后的数组大小为 15。
  • 如果扩容后的大小还是不够,那么就以添加元素的数量作为扩容大小,即新数组的大小为 oldCapacity + (oldCapacity >> 1) + 1。

需要注意的是,ArrayList 中的数组无法动态地调整大小,因此每次扩容都需要创建新的数组和复制元素,这可能会带来一些性能损失。为了避免频繁扩容,我们可以在使用 ArrayList 时尽量预估元素数量,初始化时指定一个合适的初始容量

4、泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

4.1、泛型的特点

  • 泛型可以将类型作为参数进行传递,即类型可以像参数一样实现参数化。
  • 在编译的时候检查类型安全。
  • 所有的强制转换都是自动和隐式的。
  • Java引入泛型是安全简单的,并能提高代码的重用。

4.2、泛型引入前

在没有泛型的时候,基于通用性的考虑,早期的集合类存储的都是Object类型,一个集合便可以存储任意类型的对象,因为所有对象都是Object的子类型

那么这样做会存在什么样的问题呢,我们先看一个不使用泛型的例子

例如这个程序代码段里就有一个list集合,假设在这个集合里放的是整形对象,而我们很可能不小心把字符串对象放到里面,这时编译器却无法发现其中的错误,直到程序运行时才会发现错误,但为时已晚,这种情况甚至在应用系统已经部署之后才会发生。而利用泛型就可以提前发现这些错误

4.3、泛型引入后

在编译期就已经报错了,程序员可以提前解决这问题

5、案例 (贯穿项目相关)

用List构建一组员工数据,主菜单功能:

1.查询所有员工

2.输入id查询员工

3.输入姓名关键字查询员工

4.录入新员工

5.1、创建员工操作类

工具类来实现员工基本操作

 package com.woniuxy.dao.impl;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import com.woniuxy.entity.Employee;
 
 public class EmployeeDaoImpl implements EmployeeDao {
     List<Employee> list = new ArrayList<>();
     {
         list.add(new Employee(1001, "tom", 22));
         list.add(new Employee(1002, "jerry", 23));
         list.add(new Employee(1003, "merry", 24));
     }
 
     /**
      * 查询全部
      * @return
      */
     public List<Employee> selectAll() {
         // TODO Auto-generated method stub
         return list;
     }
 
     /**
      * 根据id查询
      *
      * @param empId
      * @return
      */
     public Employee queryById(int empId) {
         Employee emp = null;
         for (int i = 0; i < list.size(); i++) {
             if(list.get(i).getEmpId()==empId) {
                 emp = list.get(i);
             }
         }
         return emp;
     }
     /**
      * 根据关键字查询
      *
      * @param empName
      * @return
      */
     public Employee queryByName(String empName) {
         Employee emp = null;
         for (int i = 0; i < list.size(); i++) {
             if(list.get(i).getEmpName().contains(empName)) {
                 emp = list.get(i);
             }
         }
         return emp;
     }
     /**
      * 添加员工
      *
      * @param employee
      * @return
      */
     public int addEmployee(Employee employee) {
         list.add(employee);
         return 1;
     }
 
 }

5.2、创建控制台

注意:整个程序中必须一直使用同一个Scanner,如果使用两个,其中一个关闭之后 ,另一个继续读取时就会抛异常java.util.NoSuchElementException,参考

 package com.woniuxy.dao.impl;
 
 import java.util.List;
 import java.util.Scanner;
 
 import com.woniuxy.entity.Employee;
 
 public class Main {
 
     public static void main(String[] args) {
         EmployeeDao employeeDao = new EmployeeDaoImpl();
         Scanner sc = new Scanner(System.in);
         while (true) {
             // 欢迎菜单
             System.out.println("------------蜗牛人事管理系统------------");
             System.out.println("------------请选择操作菜单------------");
             System.out.print("1.查询所有员工 ");
             System.out.print("2.根据id查询员工  ");
             System.out.print("3.新增员工 ");
             System.out.print("4.按姓名序查询 ");             System.out.print("9.退出 ");
             System.out.println("");             // 键盘输入operNum
 
             int operNum = sc.nextInt();
             if (operNum == 9) {
                 sc.close();
                 break;
             } else if (operNum == 1) {// 查询所有员工
                 List<Employee> list = employeeDao.selectAll();
                 for (int i = 0; i < list.size(); i++) {
                     System.out.println(list.get(i));
                 }
 
             } else if (operNum == 2) {// 根据id查询员工
                 System.out.println("请输入要查询的员工编号");
                 int empId = sc.nextInt();
                 Employee employee = employeeDao.queryById(empId);
                 System.out.println("查询到的员工信息:" + employee);
 
             } else if (operNum == 3) {// 新增员工
                 Employee employee = new Employee();
                 System.out.println("请输入员工编号");
                 int empId = sc.nextInt();
                 employee.setEmpId(empId);
 
                 System.out.println("请输入员工姓名");
                 String empName = sc.next();
                 employee.setEmpName(empName);
 
                 System.out.println("请输入员工年龄");
                 int age = sc.nextInt();
                 employee.setAge(age);
                 employeeDao.addEmployee(employee);
                 System.out.println("添加成功");
 
             }else if (operNum == 4) {// 按姓名序查询
                 System.out.println("请输新的入员工姓名");
                 String empName = sc.next();
                 Employee employee = employeeDao.queryByName(empName);
                 System.out.println(employee);
 
             }else {
                 System.out.println("请输入正确的数字");
             }
 
         }
 
     }
 
 }

6、迭代器

foreach其实是语法糖,底层就是基于Iterator来实现的

迭代器是一种设计模式,它是一个对象,它可以遍历并选择集合中的对象,而开发人员不需要了解该集合的底层结构

Java中的Iterator功能比较简单,只能单向移动:

  • 使用方法iterator()要求容器返回一个Iterator。
  • 第一次调用Iterator的next()方法时,它返回序列的第一个元素。
  • 使用next()获得序列中的下一个元素。
  • 使用hasNext()检查序列中是否还有元素。
  • 使用remove()将迭代器所指向的集合删除元素。

Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素

7、案例 (贯穿项目相关)

见第八天最后一例,改用迭代器实现功能:

输入id删除员工.

录入新员工时,用try-catch防止非法输入,特别是年龄.

输入-1时,抛出年龄太小异常.

7.1、删除员工操作类

注意,使用list的remove删除时,不能删除集合中最后一个元素,否则会报异常,参考

我们要实现删除集合中的元素要使用iterator.remove();来实现

添加删除操作方法

 /**
      * 删除操作
      *
      * @param empId
      * @return
      */
     @Override
     public int deleteEmp(int id) {
         Iterator<Employee> iterator = list.iterator();
         while(iterator.hasNext()) {
             Employee emp = iterator.next();
             if(emp.getId()==id) {
                 //list.remove(emp); //remove删除时不能删除最后一条
                 iterator.remove();
             }         }
         return 1;
     }

方式二:

不使用foreach,使用for循环来处理,通过下标找到,并通过下标删除

 @Override
     public int deleteEmp(int empId) {
         for (int i = 0; i < list.size(); i++) {
             if(list.get(i).getEmpId() == empId) {
                 list.remove(i);
             }         }         return 1;
     }

7.2、创建员工操作类

工具类来实现员工基本操作

 package com.woniuxy.dao.impl;
 
 import java.util.List;
 import java.util.Scanner;
 
 import com.woniuxy.entity.Employee;
 
 public class Main {
 
     public static void main(String[] args) {
         EmployeeDao employeeDao = new EmployeeDao();
         Scanner sc = new Scanner(System.in);
         while (true) {
             // 欢迎菜单
             System.out.println("------------蜗牛人事管理系统------------");
             System.out.println("------------请选择操作菜单------------");
             System.out.print("1.查询所有员工 ");
             System.out.print("2.根据id查询员工  ");
             System.out.print("3.新增员工 ");
             System.out.print("4.按姓名序查询 ");
             System.out.print("5.删除 ");
             System.out.print("9.退出 ");
             System.out.println("");             // 键盘输入operNum
 
             int operNum = sc.nextInt();
             if (operNum == 9) {
                 sc.close();
                 break;
             } else if (operNum == 1) {// 查询所有员工
                 List<Employee> list = employeeDao.selectAll();
                 for (int i = 0; i < list.size(); i++) {
                     System.out.println(list.get(i));
                 }
 
             } else if (operNum == 2) {// 根据id查询员工
                 System.out.println("请输入要查询的员工编号");
                 int empId = sc.nextInt();
                 Employee employee = employeeDao.queryById(empId);
                 System.out.println("查询到的员工信息:" + employee);
 
             } else if (operNum == 3) {// 新增员工
                 Employee employee = new Employee();
                 System.out.println("请输入员工编号");
                 int empId = sc.nextInt();
                 employee.setEmpId(empId);
 
                 System.out.println("请输入员工姓名");
                 String empName = sc.next();
                 employee.setEmpName(empName);
 
                 System.out.println("请输入员工年龄");
                 try {
                     int age = sc.nextInt();
                     if(age<18||age>100) {
                         throw new MyException("年龄超出了范围");
                     }
                     employee.setAge(age);
                     employeeDao.addEmployee(employee);
                     System.out.println("添加成功");                 }catch (Exception e) {
                     System.out.println("请输出正确的数字");
                 } 
             }else if (operNum == 4) {// 按姓名序查询
                 System.out.println("请输新的入员工姓名");
                 String empName = sc.next();
                 Employee employee = employeeDao.queryByName(empName);
                 System.out.println(employee);
 
             }else if (operNum == 5) {// 删除员工
                 System.out.println("请输入要删除的员工编号");
                 int empId = sc.nextInt();
                 employeeDao.delete(empId);
                 System.out.println("删除成功");
             }else {
                 System.out.println("请输入正确的数字");
             }
 
         }
 
     }
 
 }
 

7.3、自定义异常类

 public class MyException extends RuntimeException {
     /**
      *
      */
     private static final long serialVersionUID = 1L;
     public MyException() {
         // TODO Auto-generated constructor stub
     }
     public MyException(String message) {
         super(message);
     }
 
 }

三、LinkedList

java.util.LinkedList集合数据存储的结构是链表结构,方便元素添加、删除的集合。

LinkedList是一个双向链表

1、什么是链表(了解)

定义:

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的

链表通常是由一串节点(链节点)组成,每个节点包含任意的实例数据(data fields)和一或两个用来指向上一个或下一个节点的位置链接(links)也就是数据的地址(指针)。

特点:

使用链表结构可以克服数组需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理(用一个空间就加一个,没有浪费多余的空间)。但是链表失去了数组随机读取的优点,同时链表由于增加了节点的指针域,空间开销比较大。

链表是一种插入和删除都比较快的数据结构,缺点是查找比较慢。除非需要频繁的通过下标来随机访问数据,否则在很多使用数组的地方都可以用链表代替。

分类:

从实现方式可以分为单向链表、双向链表、循环链表

还有一种划分带头和不带头:

带头:头节点只存储下一个节点为的引用,不存储数据

不带头:头节点即存储数据又存储下一个节点为的引用

我们以带头为列,head为头节点,不存放任何数据,只存放指向链表中真正存放数据的第一个节点的地址,充当指针

单向链表:指的是链表中的节点指向只能指向下一个节点或者为空,节点之间不能相互指向。

双向链表:链表中,每个链表节点既有指向下一个节点的指针,又有指向前一个节点的指针,即每个节点都有两种指针。

循环链表:指的是在单向链表和双向链表的基础上,将两种链表的最后一个节点指向第一个节点从而实现循环。(双向链表中第一个节点中存在指向最后一个节点的指针)

2、LinkedList

LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,而是存储在单独的节点中,然后通过引用将节点连接起来了,因此在任意位置插入或者删除元素时,不需要搬移元素,效率比较高

  • LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
  • LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
  • LinkedList比较适合任意位置插入的场景

3、LinkedList常用方法

方法 说明
public void addFirst(E e) 将指定元素插入集合的开头
public void addLast(E e) 将指定元素插入集合的结尾
public E getFirst() 返回集合第一个元素
public E getLast() 返回集合最后一个元素
public E removeFirst() 移除并返回集合的第一个元素
public E removeLast() 移除并返回最后一个元素
public E pop() 从集合所表示的堆栈中弹出一个元素
public void push(E e) 将元素推入集合所表示的堆栈中
public boolean isEmpty() 判断集合是否为空

4、List标准使用

LinkedList实现了List接口 ,所以LinkedList是具备List的存储特征的(有序、元素有重复)

public static void main(String[] args) {LinkedList<String> list = new LinkedList<>();list.add("tom");list.add("jerry");list.add("merry");Iterator<String> iterator = list.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}}

输出

tom
jerry
merry

5、非List的使用

/** 非List的使用* LinkedList在实现List的时候也添加了自己的方法* 以双向链表存储内容*/public static void main(String[] args) {LinkedList<String> linkedList = new LinkedList<>();//  在链表的第一个位置进行插入元素linkedList.addFirst("tom");linkedList.addFirst("merry");linkedList.addFirst("jerry");//  得到第一个元素System.out.println(linkedList.get(0)); // 输出jerrySystem.out.println(linkedList.get(1)); // 输出merry//  得到最后一个元素System.out.println(linkedList.getLast()); // 输出tom//  移除第一个元素linkedList.removeFirst();//  移除最后一个元素linkedList.removeLast();//   移除元素之后我们的List中就只剩下merry了//   那我们读取栈顶元素System.out.println("读取到栈顶元素:" + linkedList.peek());}

6、RandomAccess接口(了解)

RandomAccess接口是一个空接口,不包含任何方法,只是作为一个标识:

package java.util;
public interface RandomAccess {
}

实现该接口的类说明其支持快速随机访问,比如ArrayList实现了该接口,说明ArrayList支持快速随机访问。

所谓快速随机访问指的是通过元素的下标即可快速获取元素对象,无需遍历,

而LinkedList则没有这个特性,元素获取必须遍历链表。

linkedList不支持快速访问,其get方法是怎么实现的?

采用二分法遍历每个Node节点,直到找到index位置的节点

四、Vector类

1、什么是Vector

Vector和ArrayList非常相似,它们都实现了相同的接口,继承相同的类,就连方法的实现也非常类似。和ArrayList不同的是,Vector是线程安全的,关键方法上都加了synchronized同步锁,由于Vector效率不高,所以使用的较少,要使用线程安全的ArrayList,推荐CopyOnWriteArrayList。

2、ArrayList & Vector

  • Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。
  • 当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
  • ArrayList类封装了一个动态再分配的Object[]数组。每个ArrayList对象有一个capacity。这个capacity表示存储列表中元素的数组的容量。当元素添加到ArrayList时,它的capacity在常量时间内自动增加

3、示例

public static void main(String[] args) {Vector<String> vector = new Vector<>();//向该集合中添加元素vector.add("A");vector.add("B");vector.add("C");System.out.println(vector);}

五、集合排序(贯穿项目相关)

案例 (贯穿项目相关)

1.按年龄给所有员工排序(正序),并输出.

2.按年龄给所有员工排序(正序),年龄相同的相邻员工按id排序(倒序),并输出.

1、Collections类概述

Collections是针对集合操作的工具类。此类仅由静态方法组合或返回集合,静态方法可以直接通过类名调用。它包含对集合进行操作的多态算法,包装器,返回由指定集合支持的新集合,以及其他一些可能的和最终的。

最常见的操作就是通过Collections对List集合中的数据进行排序

public static void main(String[] args) {List<Integer> nums = new ArrayList<Integer>();nums.add(3);nums.add(5);nums.add(1);nums.add(0);System.out.println(nums);Collections.sort(nums);System.out.println(nums);
}

2、实现Comparable接口

被排序的实体类里面实现Comparable接口,重写compareTo()方法,在list排序的时候再调用Collections.sort(list)

  • 实体类实现Comparable接口

    compareTo()方法,该方法的返回值0代表相等,1表示大于,-1表示小于;

    public class Employee implements Comparable{
    private int empId;
    private String empName;
    private int age;
    public Employee() {
    // TODO Auto-generated constructor stub
    }
    @Override
    public int compareTo(Employee o) {
    int i = this.age - o.getAge();return i;
    }
    ……
    }
    
  • 修改查询全部操作

    public class EmployeeDaoImpl {
    /**
    * 查询全部
    *
    * @param list
    */
    public void eachList(List list) {
    //排序
    Collections.sort(list);
    Iterator it = list.iterator();
    while(it.hasNext()){System.out.println(it.next());
    }
    ……
    }
    }
    

为什么在简单例子中没有看到实现Comparable接口呢?

是因为Integer类其实自己已经实现 了Comparable接口,Java已经给我们做好了。

3、使用Comparator匿名内部类

在Collections.sort(list,Comparator)直接传Comparator匿名函数

sort(List<T> list, Comparator<? super T> c)    根据指定比较器产生的顺序对指定列表进行排序
  • 修改查询全部操作

    public class EmployeeDaoImpl {
    /**
    * 查询全部
    *
    * @param list
    */
    public void eachList(List list) {
    Collections.sort(list,new Comparator() {
    @Override
    public int compare(Employee o1, Employee o2) {
    int i = o1.getAge() - o2.getAge(); //先按照年龄排序
    if(i==0) {
    return o1.getEmpId() - o2.getEmpId(); //如果年龄相等再根据id升序进行排
    }
    return i;
    }
    });
    Iterator it = list.iterator();
    while(it.hasNext()){
    System.out.println(it.next());
    }
    ……
    }
    
  • 如何想根据id倒序排序怎么办?

参数Comparator.reverseOrder()是倒序,Collections.sort(list, Comparator.reverseOrder());

便此种方式实现比较麻烦,最简单的办法就是调整一下o1.getEmpId() - o2.getEmpId()的顺序,代码如下

public class EmployeeDaoImpl {/*** 查询全部** @param list*/public void eachList(List<Employee> list) {Collections.sort(list,new Comparator<Employee>() {@Overridepublic int compare(Employee o1, Employee o2) {int i = o1.getAge() - o2.getAge(); //先按照年龄排序if(i==0) {return o2.getEmpId() - o1.getEmpId(); //如果年龄相等再根据id降序进行排}return i;}});Iterator<Employee> it = list.iterator();while(it.hasNext()){System.out.println(it.next());}}……
}

4、使用List接口自带的sort方法

该方法是自JDK1.8引入,实现方式上面的基本一样

default void sort(Comparator<? super E> c) 使用随附的 Comparator排序此列表来比较元素。
public class Demo {public static void main(String[] args) {ArrayList<Emp> list = new ArrayList<>();list.add(new Emp(1001, "tom", 22));list.add(new Emp(1001, "tomm", 18));list.add(new Emp(1001, "tommm", 25));list.add(new Emp(1001, "tommmm", 21));list.sort(new Comparator<Emp>() {@Overridepublic int compare(Emp o1, Emp o2) {return o1.getAge()-o2.getAge();//根据年龄比较}});//打印结果for (Emp emp : list) {System.out.println(emp);}}}

思维导图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/908712.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

时序数据库 IoTDB 荣获第八届中关村国际前沿科技大赛工业互联网领域赛 Top3

3 月 28 日,第八届中关村国际前沿科技大赛总决赛暨颁奖典礼在北京中关村展示中心隆重举行。天谋科技(北京)有限公司(简称“天谋科技”)的“工业物联网时序数据库 IoTDB”项目经过层层选拔,从 3200 多个参赛项目中脱颖而出,最终荣获工业互联网领域赛第三名,获颁“第八届…

库卡工业机械手本体线缆维修技巧

随着工业自动化的发展,库卡机器人作为先进的自动化设备,广泛应用于各个领域。然而,在使用过程中,机器人本体线缆的损坏和老化是不可避免的。因此,进行KUKA机械手本体线缆维修和保养至关重要。 一、常见的库卡机械手线缆故障 1. 线缆老化:长时间使用后,线缆外皮会出现老化…

CH592段式LCD

段式LCD的显示跟屏幕有关。CH592x开发板的屏幕规格,SEG和COM如图:可以参数配置为0xF0/0X0F,查看显示效果:

Powerjob学习记录

一前言 本文章仅为个人学习总结记录,更多内容可直接访问Powerjob官方开源大佬的github或官方在线文档 官方github地址:https://github.com/PowerJob/PowerJob 官方在线文档:https://www.yuque.com/powerjob/guidence/quick_start 二 产品特性 PowerJob(原OhMyScheduler)是…

角球预测方法:基于模糊区域划分与可解释增强模型的概率估计

​引言 在现代竞技运动中,量化评估运动员表现一直是数据分析领域的核心挑战。由于得分事件相对稀少,传统基于简单计数的统计方法往往无法准确反映运动员对比赛结果的实际贡献。近年来,随着事件数据采集技术的进步,基于期望值的表现评估方法逐渐成为研究热点,其中角球情境下…

算法备案能加急办理吗?

首先明确一点,算法备案官方审核部门是没有所谓的渠道提供快速审核服务的,所有申请者都是一视同仁。其次,我们确实有办法提高审核效率,加快算法备案进度。大家要注意识别所谓的加速办理是哪种情况以下是一些算法备案审核周期的重要信息,供大家参考:一、算法备案官方周期 1…

Windows11+OBS+视频号+麦克风设置直播操作流程

OBS+视频号直播操作流程 一、前期准备 1、可用于直播的电脑,我的是Win11系统 2、硬件设备(相机、采集卡、麦克风等) 3、软件(微信、OBS) 4、虚拟声卡 注:这个教程主要说一下声卡的配置,所以相机和采集卡之类的没有讲到 二、软件安装 微信和OBS这个都不会安装就别折腾了,所…

2025年天梯赛补题记录——整数的持续性

为什么没写出来:哈哈,看到400ms就不想写了,被前面一个题目卡了两次时间心态崩了,头脑发昏以为直接算过去会超时(能说那个时候快困死了脑袋很不灵光吗,给自己的无能找借口嘻嘻) 优化思路: 1.记忆化缓存:一想便知道每个数的分解都算一次很费时间,可以联想到记忆化缓存—…

《上古卷轴3:晨风》——存档技能数据修改

《上古卷轴3:晨风》由于其mod广泛开发,使得游戏的生命力非常强大,至今仍受广大RPG迷的喜爱!但晨风的技能数据如果用CE去修改,则是无用的。这里提供了技能数据的存档顺序,因此可以利用hex editor类的软件直接修改存档CE修改失效 《上古卷轴3:晨风》由于其mod广泛开发,使…

记录一次Armbian安装宝塔面板遇到ModuleNotFoundError: No module named _sqlite3的问题

如果在用Armbian安装宝塔面板的时候遇到ModuleNotFoundError: No module named _sqlite3报错,并且无法进入web面板界面,可以尝试以下操作。报错界面展示:步骤1:更换或添加Ubuntu软件源地址到/etc/apt/source.list.d文件夹的文件中 例如:将下面的地址添加到/etc/apt/source…

Cesium中glb模型颜色暗淡解决

问题: 3dmax导出fbx,此fbx文件导入blender中,再由blender导出成glb模型,该glb模型放入cesium中贴图颜色颜色暗沉无光,试了各种办法(泛光、时差、多光源、唯一光)效果均不明显。 原因: 发现,转格式过程中不知道哪一环出错,会导致模型材质一个叫metallicFactor的属性格…