关于【集合】的一些问题

目录

11.关于HashMap和TreeMap的排序问题

众所周知,HashMap是无序的,不能对HashMap进行排序(起码目前还不知道).但是这并不代表Map就一定是无序的! 没错本次提到的排序就是利用了TreeMap进行排序.

11.1.TreeMap特性

转自:https://blog.youkuaiyun.com/qq_32166627/article/details/72773293 源码分析,方法使用等还是看原文链接,这里仅展示概念

前言
TreeMap的基本概念:

TreeMap集合是基于红黑树(Red-Black tree)的 NavigableMap实现。该集合最重要的特点就是可排序,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。这句话是什么意思呢?就是说TreeMap可以对添加进来的元素进行排序,可以按照默认的排序方式,也可以自己指定排序方式。

根据上一条,我们要想使用TreeMap存储并排序我们自定义的类(如User类),那么必须自己定义比较机制:一种方式是User类去实现java.lang.Comparable接口,并实现其compareTo()方法。另一种方式是写一个类(如MyCompatator)去实现java.util.Comparator接口,并实现compare()方法,然后将MyCompatator类实例对象作为TreeMap的构造方法参数进行传参(当然也可以使用匿名内部类),这些比较方法是怎么被调用的将在源码中讲解。

下图是Map集合体系类图。
在这里插入图片描述
总结
TreeMap继承了Map的性质,同时其树结构又可以进行元素排序,用处很大。

11.2.java如何对Map进行排序

转自:https://blog.youkuaiyun.com/m0_51051154/article/details/120392110

Map排序(按key排序,按value排序)

主要分两种,按键排序、按值排序。 而且,按key排序主要用于TreeMap,而按value排序则对于Map的子类们都适用。

一、按键排序

按Key排序主要用于TreeMap`,可以实现按照Key值的大小,在对象插入时直接插入到合适的位置,保持Map的顺序性。

来看TreeMap的构造函数:TreeMap(Comparator<? super K> comparator):构造一个新的、空的树映射,该映射根据给定比较器进行排序。

这里的比较器是key的比较器。所以定义比较器时用于比较的两个参数是Key的数据类型的对象。

实例代码如下:

public class MapSortTest {

public static void main(String[] args) {
  Map<String,String> stu=new TreeMap<>(new MyComparator());//传进来一个key的比较器对象来构造treemap
  stu.put("apple", "55");
  stu.put("boy", "32");
  stu.put("cat", "22");
  stu.put("dog", "12");
  stu.put("egg", "11");
  //map的遍历:把key抽取出来用set存放,然后用迭代器遍历keyset,同时用map.get(KEY)获取key所对应的value。

  Set<String> keySet=stu.keySet();
  Iterator it=keySet.iterator();
  while (it.hasNext()) {
    String next = (String)it.next();
    System.out.println(next+","+stu.get(next)); 
      } 
  }
}

//定义key的比较器,比较算法根据第一个参数o1,小于、等于或者大于o2分别返回负整数、0或者正整数,来决定二者存放的先后位置:返回负数则o1在前,正数则o2在前。
class MyComparator implements Comparator<String>{
  public int compare(String o1, String o2) {
    return o1.compareTo(o2); 
  }
}

二、按值排序

与按键排序只使用TreeMap不同,按值排序由于其方法所用到的类型的统一性,所以能用于Map的所有子类。

主要用到的知识点有;

1:map.entrySet()将map里的每一个键值对取出来封装成一个Entry对象并存放到一个Set里面。

2:泛型Map.Entry<type1,type2> 因为Key-value对组成Entry对象,此处指明Entry对象中这两个成员的数据类型。

3:Collections.sort(List list, Comparator<? super T> c) 集合类的排序方法,通过自定义的比较器进行排序。这里的list存放的对象是entry对象。定义比较器对entry对象中的value属性进行比较。

实例代码如下:

public class MapSortTest {
  public static void main(String[] args) {
    Map<String,String> stu=new TreeMap<>();//用TreeMap储存

    // Map<String,String> stu=new HashMap<>();//用HashMap储存

    stu.put("apple", "55");
    stu.put("boy", "32");
    stu.put("cat", "22");
    stu.put("dog", "12");
    stu.put("egg", "11");

    //1:把map转换成entryset,再转换成保存Entry对象的list。
    List<Map.Entry<String,String>> entrys=new ArrayList<>(stu.entrySet());
    //2:调用Collections.sort(list,comparator)方法把Entry-list排序
    Collections.sort(entrys, new MyComparator());
    //3:遍历排好序的Entry-list,可得到按顺序输出的结果
    for(Map.Entry<String,String> entry:entrys){
      System.out.println(entry.getKey()+","+entry.getValue());
        }
      }
  }

  //自定义Entry对象的比较器。每个Entry对象可通过getKey()、getValue()获得Key或Value用于比较。换言之:我们也可以通过Entry对象实现按Key排序。
  class MyComparator implements Comparator<Map.Entry>{
    public int compare(Map.Entry o1, Map.Entry o2) {
      return ((String)o1.getValue()).compareTo((String)o2.getValue());
      } 
    }

10.关于在List集合首部插入一条复制的数据

需求分析
1.复制第一条数据,然后插入到第一条数据之后,新插入的数据,有两个字段需要手动置空
2.在第一条的基础上,向后,置空第一条数据之后所有数据中的两个字段

第一种: 这种方法比较笨,且不是正常的写法,但是这种写法有利于入门,并加深对List的理解,实际运用看第二种

List<PastBusiness> pastBusinessList = pastBusinessMapper.selectListByIdAndEId(approval.getApprovalId(),externalId);
        // 在集合首部插入复制的第一条数据
        for (int i = pastBusinessList.size() - 1; i >= 0; i--) {
            PastBusiness pastBusiness = pastBusinessList.get(i);
            // 置空第一条数据之后的提交人信息
            if (i != 0) {
                pastBusiness.setSubmitterTime(null);
                pastBusiness.setSubmitter(null);
            }
            if (i+1 >= pastBusinessList.size()) {
                pastBusinessList.add(pastBusiness);
            } else {
            	// 这里存在对象的哈希地址一直的问题,所以后边置空数据的时候,会连带两条数据都置空,
            	// 所以这里新new一个对象,进行塞值
                if (i == 0) {
                    PastBusiness pastBusiness1 = new PastBusiness();
                    BeanUtils.copyProperties(pastBusiness,pastBusiness1);
                    pastBusinessList.set(i + 1,pastBusiness1);
                } else {
                    pastBusinessList.set(i + 1, pastBusiness);
                }
            }
        }
        // 置空第二条数据的提交人信息
        pastBusinessList.get(1).setSubmitter(null);
        pastBusinessList.get(1).setSubmitterTime(null);

        return pastBusinessList;

第二种: 经历优化后的解决办法

需求分析
3.这里新增了一条需求: 在上文1. 2.的基础上,如果遇到特定的字段值发生了改变,就执行一下复制当前值并插入到后边

注意代码中,对数据的判断,主要优化 合并的就是这些判断

// 在集合首部插入复制的第一条数据
            for (int i = 0; i < pastBusinessList.size(); i++) {
                PastBusiness pastBusiness = pastBusinessList.get(i);
                if (i == 0 || pastBusiness.getApprovalNumber() != pastBusinessList.get(i - 1).getApprovalNumber()) {
                    // 处理数据插入
                    PastBusiness pastBusiness1 = new PastBusiness();
                    BeanUtils.copyProperties(pastBusiness, pastBusiness1);
                    pastBusiness1.setSubmitter(null);
                    pastBusiness1.setSubmitterTime(null);
                    pastBusinessList.add(i + 1, pastBusiness1);
                    i++;  // 向后挪动一个下标
                } else {
                    // 置空数据
                    pastBusiness.setSubmitter(null);
                    pastBusiness.setSubmitterTime(null);
                }
            }
        }
        return pastBusinessList;

10.1.原理解析

java ArrayList数组使用add来插入一个元素,新数据下标为,i+1,实例如下:

import java.util.ArrayList;
public class Test {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(0);//插入第一个元素
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        System.out.println(list);//打印list数组
        list.add(2, 7);
        System.out.println(list);
    }
}

运行结果如下:
在这里插入图片描述

9.list的forEach用法

List<StatisticsObjectAndDoubleDTO> inStockList = null;
if (inStockList != null && !inStockList.isEmpty()) {
            Map<String,Double> inStockMap = new HashMap<>();
            inStockList.forEach(inStock -> {
                inStockMap.put((String) inStock.getName(),inStock.getNum());
            });
            statisticsChartVO.setInStockMap(inStockMap);
        }

8.lambda – 过滤list中对象的某个属性非空,然后返回一个新的list

stream流详解(JDK1.8的特性)

package com.example.demo.util;

import com.example.demo.entity.UserPO;
import com.google.common.collect.Maps;

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

/**
 * 过滤list中对象的某个属性非空,然后返回一个新的list
 */
public class LambdaForList {
    public static void main(String[] args) {
        //1. 初始化数据
        UserPO user1 = new UserPO(1, "java");
        UserPO user2 = new UserPO(2, "C");
        UserPO user3 = new UserPO(null, "PHP");
        List<UserPO> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);
        users.add(user3);

        //2. 过滤list中对象的某个属性非空,然后返回一个新的list
        List<UserPO> newUsers = users.stream()
                .filter((UserPO user) -> user.getId() !=null).collect(Collectors.toList());

        newUsers.forEach((UserPO user) ->
                System.out.println(user.getName() + "--->" + user.getId()
        ));
    }
}

输出

java--->1
C--->2

7.获取集合中最大值,list中对象的某个属性的最大值最小值平均值以及筛选

获取集合中最大值最小值

一、 普通集合

1、 查询集合中字符串的个数最多和最少
List<String> strs = new ArrayList<String>();
	strs.add("a");
	strs.add("ab");
	strs.add("qwrrrrrrr");
	strs.add("qrqw");
	strs.add("qweqw");
	strs.add("aqw");
	
	System.out.println("最大值: " + Collections.max(strs));
    System.out.println("最小值: " + Collections.min(strs));
2、 查询集合中数字的最大值和最小值
List<Integer> inte = new ArrayList<Integer>();
	inte.add(1);
	inte.add(23);
	inte.add(56);
	inte.add(2);
	inte.add(346);
	inte.add(2);
	
	System.out.println("最大值: " + Collections.max(inte));
	System.out.println("最小值: " + Collections.min(inte));

二、 集合中存放对象时查询对象中的某个属性的最大值最小值。

1. 创建一个实体类User
package com.list.max.min;

public class User {
	private String name;//用户姓名
	private Integer age;//用户年龄
	public User() {
		super();
	}
	public User(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}
}
2. list中对象的某个属性的最大值最小值平均值以及筛选
package com.list.max.min;

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

/**
 *	list中对象的某个属性的最大值最小值平均值以及筛选
 * @author Administrator
 *
 */
public class ListMaxMinTest {
	
	public static void main(String[] args) {
		List<User> users = new ArrayList<User>();
		User user01 = new User("张三", 18);
		User user02 = new User("李四", 12);
		User user03 = new User("王五", 26);
		User user04 = new User("赵六", 50);
		User user05 = new User("钱七", 37);
		users.add(user01);
		users.add(user02);
		users.add(user03);
		users.add(user04);
		users.add(user05);
		
		//查询年龄最大的用户
		User maxAgeUser = users.stream().max(Comparator.comparing(User::getAge)).get();
		//查询年龄最大的用户的年龄方式一
		int maxAge01 = users.stream().max(Comparator.comparing(User::getAge)).get().getAge();
		System.out.println("最大年龄的人maxAgeUser==="+maxAgeUser);
		System.out.println("最大年龄的人的年龄maxAge01方式一==="+maxAge01);
		//查询年龄最大的用户的年龄方式二
		double maxAge02 = users.stream().mapToDouble(User::getAge).max().getAsDouble();
		System.out.println("最大年龄的人的年龄maxAge02方式二==="+maxAge02);
		
		
		//查询年龄最小的用户
		User minAgeUser = users.stream().min(Comparator.comparing(User::getAge)).get();
		//查询年龄最小的用户的年龄方式一
		int minAge01 = users.stream().min(Comparator.comparing(User::getAge)).get().getAge();
		System.out.println("最小年龄的人minAgeUser==="+minAgeUser);
		System.out.println("最小年龄的人minAge01==="+minAge01);
		//查询年龄最小的用户的年龄方式二
		double minAge02 = users.stream().mapToDouble(User::getAge).min().getAsDouble();
		System.out.println("最小年龄的人minAge02==="+minAge02);
		
		
		//获取年龄总和方式一
		int sumAge01 = users.stream().collect(Collectors.summingInt(User::getAge));
		System.out.println("所有人的年龄总和sumAge01==="+sumAge01);
		//获得年龄的总和方式二
        int sumAge02 = users.stream().mapToInt(User -> User.getAge()).sum();
        System.out.println("所有人的年龄总和sumAge02===="+sumAge02);
		//获得年龄的总和方式三
		double sumAge03 = users.stream().mapToDouble(User::getAge).sum();
		System.out.println("所有人的年龄总和sumAge03===="+sumAge03);
		
		
        //获得年龄的平均值方式一
        double avgAge01 = users.stream().mapToInt(User -> User.getAge()).average().getAsDouble();
        System.out.println("所有人的年龄平均值avgAge01===="+avgAge01);
		//获得年龄的平均值方式二
		double avgAge02 = users.stream().mapToDouble(User::getAge).average().getAsDouble();
		System.out.println("所有人的年龄平均值avgAge02===="+avgAge02);
		
		
        //过滤出年龄是26的user,想过滤出什么条件的都可以
        List<User> users1 = users.stream().filter(User -> User.getAge() >= 26).collect(Collectors.toList());
        System.out.println("大于等于26岁的人有users1===="+users1);
        //过滤出姓名不等于张三user,想过滤出什么条件的都可以
        List<User> users2 = users.stream().filter(User -> !User.getName().equals("张三")).collect(Collectors.toList());
        System.out.println("姓名不等于张三的人有users2===="+users2);
		
		
        //统计出年龄大于等于26的个数
        long count01 = users.stream().filter(User -> User.getAge() >= 26).count();
        System.out.println("大于等于26岁的人有多少个===="+count01);
        //统计出姓名等于张三的人的个数
		long count02 = users.stream().filter(User -> User.getName().equals("张三")).count();
		System.out.println("姓名等于张三的人有多少个===="+count02);
        
	}
}


版权声明:本标题为qq_42570364原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.youkuaiyun.com/qq_42570364/article/details/103643509

6.将List集合用字符串,逗号隔开进行拼接

先上效果:
image
直接上代码:


public class ArraySplicing {
 
 
    private static String[] array = {"张三", "李四", "王五", "撒娇", "九点十几分", "没事", "圣诞节"};
    private static String str;
 
    public static void main(String[] args) {
 
 
        List<String> list = new ArrayList<>();
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }
 
        /**
         *
         * 将集合用字符串,逗号隔开拼接
         * */
 
        //第一种方法(灵活,可以用逗号隔开,用|线隔开)
        str = StringUtils.join(list, ","); // 注意导包,import com.sun.deploy.util.StringUtils;
        System.out.println("第一种方法" + str);
 
        //第二种方法
        str = listToString1(list);
        System.out.println("第二种方法" + str);
 
        //第三种方法(灵活,可以用逗号隔开,用|线隔开)
        str = listToString2(list, ',');
        System.out.println("第三种方法" + str);
 
 
        //第四种方法
        str = listToString3(list, ",");
        System.out.println("第四种方法" + str);
 
 
        Separator separator=new Separator(",");
        //第五种方法
        str = listToString4(list, separator );
        System.out.println("第五种方法"+str);
 
    }
 
 
    public static String listToString1(List<String> list) {
        StringBuilder sb = new StringBuilder();
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                if (i < list.size() - 1) {
                    sb.append(list.get(i) + ",");
                } else {
                    sb.append(list.get(i));
                }
            }
        }
        return sb.toString();
    }
 
 
    public static String listToString2(List list, char separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i)).append(separator);
        }
        return list.isEmpty() ? "" : sb.toString().substring(0, sb.toString().length() - 1);
    }
 
 
    public static String listToString3(List list, String separator) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i));
            if (i < list.size() - 1) {
                sb.append(separator);
            }
        }
        return sb.toString();
    }
 
 
    public static class Separator {
        private String next = "";
        private String separator;
 
        public Separator(String separator) {
            this.separator = separator;
        }
 
        public String get() {
            String result = next;
            next = separator;
            return result;
        }
    }
 
    public static String listToString4(List<String> list, Separator separator) {
        StringBuilder sb = new StringBuilder();
        for (String s : list) {
            if (s != null && !"".equals(s)) {
                sb.append(separator.get()).append(s);
            }
        }
        return sb.toString();
    }

5.java中判断list是否为空的用法

1、如果想判断list是否为空,可以这么判断:

注意这里使用了 || 所以使用这种判断 为空和不为空的位置不能变换(==也不能换成!=),否则存在错误,详情见下坑:
if(null == list || list.size() ==0 ){
  //为空的情况

}else{
  //不为空的情况

}

关于这个判断非空的坑

if (null != vo.getDocumentsVOList() && vo.getDocumentsVOList().size() > 0) {

if (vo.getDocumentsVOList().size() > 0 && null != vo.getDocumentsVOList()) {

  • 注意Bug1: 是不一样的,第二种会报错,如果字段为空会在判断里报空指针.
    这里就涉及到短路与&&的用法,先判断前边,如果不生效,后边的就不会判断。这就有效避免了空指针错误,又能做判断
  • 注意Bug2: 第一种在判断空数组的时候,不能使用 || ,否则也会判断错误,因为空数组 [] 不等于null 所以第一种的第一个判断就成立了,因为 || 所以直接就成立了

2、list.isEmpty() 和 list.size()==0 有啥区别呢

没有区别 。isEmpty()判断有没有元素,而size()返回有几个元素, 如果判断一个集合有无元素 建议用isEmpty()方法.比较符合逻辑用法。

3、list!=null 跟 ! list.isEmpty()?

所以一般的判断是
if(list!=null && !list.isEmpty()){
   //不为空的情况
}else{
   //为空的情况
}

4.List转Map的三种方法

https://blog.youkuaiyun.com/linsongbin1/article/details/79801952

1.for循环

import com.google.common.base.Function;
import com.google.common.collect.Maps;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListToMap {
    public static void main(String[] args) {
        List<User> userList = new ArrayList<>();
        User user1 = new User();
        user1.setId(1L);
        user1.setAge("12");

        User user2 = new User();
        user2.setId(2L);
        user2.setAge("13");

        userList.add(user1);
        userList.add(user2);

        Map<Long, User> maps = new HashMap<>();
        for (User user : userList) {
            maps.put(user.getId(), user);
        }

        System.out.println(maps);

    }

    public static class User {
        private Long id;
        private String age;

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getAge() {
            return age;
        }

        public void setAge(String age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", age='" + age + '\'' +
                    '}';
        }
    }
}

2.使用guava

 Map<Long, User> maps = Maps.uniqueIndex(userList, new Function<User, Long>() {
            @Override
            public Long apply(User user) {
                return user.getId();
            }
   });

3.使用JDK1.8

Map<Long, User> maps = userList.stream().collect(Collectors.toMap(User::getId,Function.identity()));

看来还是使用JDK 1.8方便一些。另外,转换成map的时候,可能出现key一样的情况,如果不指定一个覆盖规则,上面的代码是会报错的。转成map的时候,最好使用下面的方式:

Map<Long, User> maps = userList.stream().collect(Collectors.toMap(User::getId, Function.identity(), (key1, key2) -> key2));

有时候,希望得到的map的值不是对象,而是对象的某个属性,那么可以用下面的方式:

Map<Long, String> maps = userList.stream().collect(Collectors.toMap(User::getId, User::getAge, (key1, key2) -> key2));

3.List集合移除/删除元素

https://blog.youkuaiyun.com/zhaozuhao110/article/details/88116831.
List 移除某个元素
四种方式:

  • 方式一,使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除。
  • 方式二,倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除。
  • 方式三,正序遍历 List ,如果找到元素,则使用 remove 方法进行移除,然后进行索引 “自减”。
  • 方式四,使用jdk1.8新增的Stream流操作

1.Iterator 迭代器

@Test
    public void fun9(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        // 获取迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String str = it.next();
            if("关羽".equals(str)){
                it.remove();
            }
        }
        System.out.println(list);
    }

2.倒序遍历

@Test
    public void fun10(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = list.size() - 1; i > 0; i--) {
            if("关羽".equals(list.get(i))){
                list.remove(i);
            }
        }
        System.out.println(list);
    }

3.正序遍历

 	@Test
    public void fun11(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = 0; i < list.size(); i++) {
            if("关羽".equals(list.get(i))){
                list.remove(i);
                i--;
            }
        }
        System.out.println(list);
    }

4.Stream流操作(JDK 1.8 +)

	@Test
    public void fun8(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        // 筛选出不是“关羽” 的集合
        list = list.stream().filter(e -> !"关羽".equals(e)).collect(Collectors.toList());
        System.out.println("method4|list=" + list);

    }

问题:

1.为什么不能使用forEach

	@Test
    public void fun5(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (String str :list) {
            if ("张飞".equals(str)){
                list.remove(str);
            }
        }
        System.out.println(list);
    }

在这里插入图片描述
原因:
foreach方式遍历元素的时候,是生成iterator,然后使用iterator遍历。在生成iterator的时候,会保存一个expectedModCount参数,这个是生成iterator的时候List中修改元素的次数。如果你在遍历过程中删除元素,List中modCount就会变化,如果这个modCount和exceptedModCount不一致,就会抛出异常。这个是为了安全的考虑。如果使用iterator遍历过程中,使用List修改了元素,可能会出现不正常的现象。如果使用iterator的remove方法则会正常,因为iterator的remove方法会在内部调用List的remove方法,但是会修改excepedModCount的值,因此会正常运行。

2.为什么forEach 删除倒数第二元素不会出现异常

	@Test
    public void fun12() {
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (String str:list) {
            if("关羽".equals(str)){
                list.remove(str);
            }
            System.out.println(str);
        }
    }

在这里插入图片描述
仔细观察发现集合最后一个元素(“张飞”)并没有被遍历出来,因为当我们移除倒数第二个元素(“关羽”)时 cursor(游标)为 4 ,list 中size 属性的值会发生变化(5 - 1 = 4)变为 4,所以下面代码返回 false ,也就不会继续向下遍历。这也是能够正常执行的原因,因为如果继续遍历就会出现问题1 中的情况,在进行checkForComodification() 时,因为 modCount 发生了变化,而expectedModCount 并没有发生变化,所以会出现 ConcurrentModificationException异常。

public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
 public boolean hasNext() {
            return cursor != size;
        }
public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

3.普通正序 for 循环为什么要 i –

因为遍历过程中进行remove 操作时,该位置后面的元素会挤到前面来,这时候会发生一种情况就是原来元素的位置会被他后面的元素取代,而该位置已经遍历过了,所以该元素不会背遍历。 所以要进行 i-- 操作从该位置重新遍历。

	@Test
    public void fun11(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
            if("关羽".equals(list.get(i))){
                list.remove(i);
            }
        }
        System.out.println(list);
    }

就是下面的情况 “张飞” 不见了…
在这里插入图片描述

4.为什么倒序for 循环可以

当我们倒序遍历元素的时候,无论删除元素之后的元素怎么移动,之前的元素对应的索引(index)是不会发生变化的,所以在删除元素的时候不会发生问题。

2.List集合按某个字段排序(Collections.sort)

package wjtest_01;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ListSort<E> {
@SuppressWarnings(“unchecked”)
public static void main(String[] args) {

	List<Student> list = new ArrayList<Student>();

	// 创建3个学生对象,年龄分别是20、19、21,并将他们依次放入List中
	Student s1 = new Student();
	s1.setAge(20);
	s1.setUsable(true);
	Student s2 = new Student();
	s2.setAge(19);
	s2.setUsable(true);
	Student s3 = new Student();
	s3.setAge(21);
	s3.setUsable(false);
	list.add(s1);
	list.add(s2);
	list.add(s3);

	System.out.println("排序前:" + list);
  Collections.sort(list, new Comparator<Student>() {```
  	@Override
  	public int compare(Student o1, Student o2) {
  		// 按照学生的年龄进行升序排列
  		if (o1.getAge() > o2.getAge()) {
  			return 1;
  		}
  		if (o1.getAge() == o2.getAge()) {
  			return 0;
  		}
  		return -1;
  	}
  });

		System.out.println("升序排序后:" + list);

> 	Collections.sort(list, new Comparator<Student>() {
> 
> 			public int compare(Student o1, Student o2) {
> 
> 				// 按照学生的年龄进行降序排列
> 				if (o1.getAge() > o2.getAge()) {
> 					return -1;
> 				}
> 				if (o1.getAge() == o2.getAge()) {
> 					return 0;
> 				}
> 				return 1;
> 			}
> 		});

		System.out.println("降序排序后:" + list);

		Boolean b1 = true; // 创建Boolean对象1

		Boolean b2 = false; // 创建Boolean对象0

		Boolean b3 = true; // 创建Boolean对象1
		System.out.println(b1);

		int i;

		i = b1.compareTo(b2); // b1和b2进行比较  

		System.out.println(i);//1-0 

		i = b2.compareTo(b1); // b2和b1进行比较

		System.out.println(i);//0-1

		i = b1.compareTo(b3); // b1和b3进行比较

		System.out.println(i);//1-1
	}
}

class Student{  
    
    private int age;
    
    private Boolean isUsable;

	public int getAge() {  
        return age;  
    }  
  
    public Boolean isUsable() {
		return isUsable;
	}

	public void setUsable(Boolean isUsable) {
		this.isUsable = isUsable;
	}

	public void setAge(int age) {  
        this.age = age;  
    }  
    @Override  
    public String toString() {  
        return getAge()+"";  
    }  
}
转载自:https://blog.csdn.net/wangjuan_01/article/details/51351633
若有侵权,请告知删除。
-----------------------------------
List集合按某个字段排序(Collections.sort)
https://blog.51cto.com/82711020/2094455

1.List集合求差集/并集

@Override
public List<InstitutionVO> findAllByUnit(String id) {
	List<InstitutionVO> vos = new ArrayList<InstitutionVO>();
	ArrayList<String> strings = new ArrayList<>();
	List<Institution> institutionList = institutionRepository.findAllByUnit(id);  //自身及下级
	List<Institution> institutionAllList = institutionRepository.findAllByUnit(); //全部
	// 重点
	if(CollectionUtils.isNotEmpty(institutionList)) {
		for (Institution institution : institutionList) {
			strings.add(institution.getId());
		}
		for (Institution institution : institutionAllList) {
			if (!strings.contains(institution.getId())) {
				InstitutionVO vo = parseInstitutionVO(institution);
				vos.add(vo);
			}
		}
	}
	return vos;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值