List排序
1、new ArrayList().stream().sorted().collect():返回新的有序集合,原集合顺序不变。
2、new ArrayList().sort():返回void,原集合顺序变为有序。
public class Subject {
String name;
Double grade;
}
List<Subject> subjectList = new ArrayList<>();
List<Subject> subjectListNew = new ArrayList<>();
//原集合变化(升序排列)
subjectList.sort((s1, s2) -> s1.getGrade().compareTo(s2.getGrade()));
//---------------------------------------------------------------------
//原集合没变(升序排列)
subjectListNew = subjectList.stream().sorted((s1, s2) -> s1.getGrade().compareTo(s2.getGrade())).collect(Collectors.toList());
//分数升序排列
subjectListNew = subjectList.stream().sorted((s1, s2) -> {
return s1.getGrade().compareTo(s2.getGrade());
}).collect(Collectors.toList());
//分数降序排列
subjectListNew = subjectList.stream().sorted(Comparator.comparingDouble(Subject::getGrade).reversed()).collect(Collectors.toList());
//分数升序排列
subjectListNew = subjectList.stream().sorted(Comparator.comparingDouble(Subject::getGrade)).collect(Collectors.toList());
参考:List两种排序方法,sort,stream_liststream排序_二十六画生的博客的博客-优快云博客
List删除List
/**
* 从listA里删除listB里有的数据
* @param listA
* @param listB
* @return
*/
public static List<String> listrem(List<String> listA,List<String> listB){
HashSet hs1 = new HashSet(listA);
HashSet hs2 = new HashSet(listB);
hs1.removeAll(hs2);
List<String> listC = new ArrayList<String>();
listC.addAll(hs1);
return listC;
}
数组和List互换
数组转List
Arrays.asList(strArray)
// 数组转List
String[] strArray = { "a", "b" };
List<String> strList = Arrays.asList(strArray);
注意:该方法的返回值是java.util.Arrays类中一个私有静态内部类java.util.Arrays.ArrayList,它并非java.util.ArrayList类。
java.util.Arrays.ArrayList类具有set(),get(),contains()等方法,但是不支持添加add()或删除remove()方法,调用这些方法会报错。
解决方法:新建一个List对象,并且加入返回的strList,然后再add新元素
List<String> strListNew = new ArrayList<>(strList);
strListNew.add("new data");
3种基本类型数组转为List
int, long, double可以通过Java8提供的新特性stream转换:
list = Arrays.stream(arrays).boxed().collect(Collectors.toList());
// 3种基本类型数组转为List
new int[] i = { 1, 2, 3};
List<Integer> intList= Arrays.stream(i).boxed().collect(Collectors.toList());
new long[] l = { 1, 2, 3 };
List<Long> longList= Arrays.stream(l).boxed().collect(Collectors.toList());
new double[] d = { 1, 2, 3 };
List<Double> doubleList= Arrays.stream(d).boxed().collect(Collectors.toList());
String数组
String[] arrays = {"tom", "jack", "kate"};
List<String> stringList= Stream.of(arrays).collect(Collectors.toList());
Collections.addAll(arrayList, strArray)
ArrayList< String> arrayList = new ArrayList<String>(strArray.length);
Collections.addAll(arrayList, strArray);
List转数组
toArray():无参数toArray方法,这里注意不能强转,可能会出现报错。
toArray(T[] a):泛型的toArray方法要注意类型必须是包装类型,基本类型是不行的。
List<Integer> list = new ArrayList();
Integer[] array = new Integer[list.size()];
list.toArray(array);
List转String
String s = StringUtils.join(list,",");
注意:需要引入org.apache.commons.lang.StringUtils 包
List<Object>强制转换为List<String>
转换方法:List<String> strs = (List<String>)(List)object
Map所有的value转化为List
Map<String, T> map;
List<T> list = map.values().stream().collect(Collectors.toList());
一个元素转换成集合
// 1、通过Collections.singletonList
List<T> list = Collections.singletonList(T);
// 2、通过Stream
List<K> authcChannels = Stream.of(K).collect(Collectors.toList());
判断不为空
CollectionUtils.isNotEmpty(list);
翻转List
String str = "as/df/gh/jkl";
String[] str1 = str.split("/");
Collections.reverse(Arrays.asList(str1));
List分批处理切割
//按每3个一组分割
private static final Integer MAX_NUMBER = 3;
/**
* 计算切分次数
*/
private static Integer countStep(Integer size) {
return (size + MAX_NUMBER - 1) / MAX_NUMBER;
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
int limit = countStep(list.size());
//方法一:使用流遍历操作
List<List<Integer>> mglist = new ArrayList<>();
Stream.iterate(0, n -> n + 1).limit(limit).forEach(i -> {
mglist.add(list.stream().skip(i * MAX_NUMBER).limit(MAX_NUMBER).collect(Collectors.toList()));
});
System.out.println(mglist);
//方法二:获取分割后的集合
List<List<Integer>> splitList = Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a -> list.stream().skip(a * MAX_NUMBER).limit(MAX_NUMBER).parallel().collect(Collectors.toList())).collect(Collectors.toList());
System.out.println(splitList);
}
参考:java8 Stream 大数据量List分批处理切割_stream 分批处理-优快云博客
java8的lambda表达式
1、map-用于映射每个元素到对应的结果
2、filter-用于通过设置的条件过滤出元素
3、forEach-用来迭代流中的每个数据
4、limit-用于获取指定数量的流
5、sorted-用于对流进行排序
6、Collectors-实现了很多归约操作,例如将流转换成集合和聚合元素
7、统计-主要用于int、double、long等基本类型上,产生统计结果
List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
分组
//分组
Map<String, List<User>> groupBySex = list.stream().collect(Collectors.groupingBy(User::getSex));
//分组求数量
Map<Integer, Long> map = list.stream().collect(Collectors.groupingBy(User::getAge, Collectors.counting()));
// 分组求BigDecimal的和
Map<Long, BigDecimal> map = list.stream().collect(Collectors.groupingBy(Model::getProjectId
, Collectors.collectingAndThen(Collectors.toList(), m ->
m.stream().map(Model::getCost).reduce(BigDecimal.ZERO, BigDecimalUtil::sum))));
public class BigDecimalUtil {
public static BigDecimal sum(BigDecimal... in) {
BigDecimal result = BigDecimal.ZERO;
for (int i = 0; i < in.length; i++) {
result = result.add(ifNullSet0(in[i]));
}
return result;
}
}
//多个值求和
Map<String, Model> collect =
list.parallelStream().collect(Collectors.groupingBy(Model::getMobile
, Collectors.collectingAndThen(Collectors.toList(), m -> {
BigDecimal amount = m.parallelStream().map(Model::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal winAmount = m.parallelStream().map(Model::getWinAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
Integer winCount = m.parallelStream().mapToInt(Model::getWinCount).sum();
return new Model(amount, winAmount, winCount);
})));
分组根据key值排序
private static Map<String, List<Map<String,Object>>> ListMapSort( Map<String, List<Map<String,Object>>> list){
Map<String, List<Map<String, Object>>> result = new LinkedHashMap<>();
list.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(x -> result.put(x.getKey(), x.getValue()));
return result;
}
过滤
//过滤:排除掉工号为111的用户
List<User> userCommonList = list.stream().filter(a -> !a.getJobNumber().equals("111")).collect(Collectors.toList());
// 过滤对象不为空
list.stream().filter(x -> x!=null).collect(Collectors.toList());
list.stream().filter(Objects::nonNull).collect(Collectors.toList());
// 过滤某个特定属性的对象
Optional<Cart> cartOptional = cartlist.stream().filter(item -> item.getProductId().equals(1L)).findFirst();
// 或:
Cart cart = cartlist.stream().filter(item -> item.getProductId().equals(1L)).findFirst().get();
求和
//求和
//基本类型
int sumAge = list.stream().mapToInt(User::getAge).sum();
//BigDecimal求和
BigDecimal totalQuantity = list.stream().map(User::getFamilyMemberQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal对象为null的时,报空指针的情况
/**
* 重写BigDecimal的求和方法,避免BigDecimal对象为null的时,报空指针的情况
*/
public class BigDecimalUtils {
public static BigDecimal ifNullSetZero(BigDecimal value) {
if (value != null) {
return value;
} else {
return BigDecimal.ZERO;
}
}
public static BigDecimal sum(BigDecimal ...value){
BigDecimal result = BigDecimal.ZERO;
for (int i = 0; i < value.length; i++){
result = result.add(ifNullSetZero(value[i]));
}
return result;
}
}
BigDecimal totalGrade2 = studentList.stream().map(Student::getGrade).reduce(BigDecimal.ZERO, BigDecimalUtils::sum);
//当求和的字段bigDecimal对象为null的情况,可能会报空指针。需要加过滤
BigDecimal totalGrade = studentList.stream().map(i -> {
if (i.getGrade()==null){
return BigDecimal.ZERO;
}else {
return i.getGrade();
}
}).reduce(BigDecimal.ZERO, BigDecimal::add);
最值
//最小
Date minEntryDate = list.stream().map(User::getEntryDate).min(Date::compareTo).get();
//最大
Date maxEntryDate = list.stream().map(User::getEntryDate).max(Date::compareTo).get();
List转map
/**
* List -> Map
* 需要注意的是:
* toMap 如果集合对象有重复的key,会报错Duplicate key ....
* user1,user2的id都为1。
* 可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2
*/
Map<Long, User> userMap = list.stream().collect(Collectors.toMap(User::getId, a -> a,(k1, k2)->k1));
// 只获取对象的某个属性
Map<Long, String> categoryMap = list.stream().collect(Collectors.toMap(User::getId,User::getName,(entity1,entity2) -> entity1));
排序
//排序
//单字段正序排序,根据id排序
list.stream().sorted(Comparator.comparing(User::getId));
//单字段倒序排序,根据id排序
list.stream().sorted(Comparator.comparing(User::getId).reversed());
//多字段排序,根据id,年龄排序
list.stream().sorted(Comparator.comparing(User::getId).thenComparing(User::getAge));
去重
//去重
List<Long> distinctIdList = list.stream().distinct().collect(Collectors.toList());
获取list的字段为新list
//获取list对象的某个字段组装成新list
List<Long> userIdList = list.stream().map(a -> a.getId()).collect(Collectors.toList());
批量设置list列表字段
list.stream().forEach(a -> a.setDelFlag("0"));
比较
//是否所有人的年龄大于50
boolean b = list.stream().allMatch(a -> a.getAge() > 50);
//是否有一个人的年龄大于50
boolean b = list.stream().anyMatch(a -> a.getAge() > 50);
//是否所有人的年龄都不大于50
boolean b = list.stream().noneMatch(a -> a.getAge() > 50);
截取List
// skip跳过list中的几个元素,
// limit截取list中的几个元素
//两个可以配合使用,先跳过,然后截取,也可以先截取然后跳过
List<User> users = list.stream().skip(5)limit(2);
获取List对象中子List对象
@Data
public class Student{
private String name;
private int age;
}
@Data
public class Grades {
private String name;
private List<Student> students;
}
List<Student> studentList = new ArrayList<>();
List<Grades> gradeList = new ArrayList<>();
List<Student> students = gradeList.stream().map(Grades::getStudents).reduce((v1, v2) -> {
v1.addAll(v2);
return v1;
}).get();
List<String> name = gradeList.stream().map(Grades::getStudents).reduce((v1, v2) -> {
v1.addAll(v2);
return v1;
}).get().stream().map(Student::getName).collect(Collectors.toList());
list中的对象是否包含某个属性
// exists = true,包含
boolean exists = personList.stream().anyMatch(person -> person.getName().equals("Alice"));
参考
java 8 lambda表达式list操作分组、排序、去重、过滤、求和、最值_java lambda根据某个字段分组-优快云博客
Java 报错
java.util.ConcurrentModificationException: null
报错原因
1、在迭代过程中,使用了错误的方式修改了集合或者映射。例如,在使用迭代器遍历一个 ArrayList 时,同时在另一个线程中修改了 ArrayList 的结构,比如添加或者删除元素。
2、在迭代过程中,直接使用了集合或者映射的 remove() 方法而不是迭代器的 remove() 方法。直接使用集合或者映射的 remove() 方法会导致迭代器的状态异常,从而触发此异常。
3、多线程并发操作同一个集合或者映射,且没有采取合适的同步措施。
解决
针对上述异常原因,以下是一些解决方案的建议:
1、使用迭代器的 remove() 方法来删除集合或者映射中的元素。迭代器的 remove() 方法是唯一能够在迭代过程中安全地删除元素的方法。
2、在多线程环境下操作集合或者映射时,确保采取适当的同步措施。可以使用 synchronized 关键字或者并发集合类(如 ConcurrentHashMap)来确保线程安全。
3、如果需要在迭代过程中修改集合或者映射的结构,可以考虑使用迭代器的相关方法,如 add() 或者 set() 方法。
示例
List<String> list = new ArrayList<>();
list.add("item1");
list.add("item2");
list.add("item3");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
// 在迭代过程中添加或者删除元素
iterator.remove();
}