java.util.List.subList() 使用注意事项

本文详细介绍了Java中List.subList()方法的使用注意事项及示例。解释了如何获取列表中的一部分视图,并讨论了非结构性修改和结构性修改对原列表和子列表的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java.util.List.subList() 使用注意事项

标签:Java List.SubList


subList
List subList(int fromIndex, int toIndex)
  返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。(如果 fromIndex 和 toIndex 相等,则返回的列表为空)。
  返回的列表由此列表(原列表)支持,所以,你对原来的list和返回的list做的“非结构性修改”(non-structural changes),都会影响到彼此对方
  返回的列表(子列表)支持此列表(原列表)支持的所有可选列表操作。

  此方法省去了显式范围操作(此操作通常针对数组存在)。通过传递 subList 视图而非整个列表,期望列表的任何操作可用作范围操作。

  **例如,下面的语句从列表中移除了元素的范围:
  list.subList(from, to).clear();**

  可以对 indexOf 和 lastIndexOf 构造类似的语句,而且 Collections 类中的所有算法都可以应用于 subList。

  如果支持列表(即此列表)通过任何其他方式(而不是通过返回的列表)从结构上修改,则此方法返回的列表语义将变为未定义(从结构上修改是指更改列表的大小,或者以其他方式打乱列表,使正在进行的迭代产生错误的结果)。

参数:
  fromIndex - subList 的低端(包括)
  toIndex - subList 的高端(不包括)
返回:
  列表中指定范围的视图
抛出:
  IndexOutOfBoundsException - 非法的端点值 ( fromIndex < 0 || toIndex > size || fromIndex > toIndex)

示例代码:

@Test
public void testSubList() {
  List<String> originalList = new ArrayList<String>();

  for(int i = 0; i < 5; i++){
    originalList.add(String.valueOf(i));
  }

  List<String> subList = originalList.subList(2, 4);
  for(String s : subList){
    System.out.println(s);
    //输出: 2, 3
  }
  System.out.println("-----");

  //非结构性的修改子列表subList,将会影响到原列表originalList 一同修改
  subList.set(0, "22");
  for(String s : originalList){
    System.out.println(s);
    //输出: 0, 1, 22, 3, 4
  }
  System.out.println("-----");

  //structural modification by sublist, reflect parentList
  subList.add(String.valueOf(2.5));
  for(String s : originalList){
    System.out.println(s);
    //output:0, 1, 22, ,3, 2.5, 4
  }
  System.out.println("-----");

  //non-structural modification by parentList, reflect sublist
  originalList.set(3, "33");
  for(String s : subList){
    System.out.println(s);
    //output: 22, 33, 2.5
  }
  System.out.println("-----");

  //structural modification by parentList, sublist becomes undefined(throw exception)
  originalList.add("6");
  // for(String s : subList){
    // System.out.println(s);
  // }
  subList.get(0);
}

注:最后注释的for循环以及get(0) 都会抛出异常:

java.util.ConcurrentModificationException
  at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
  at java.util.ArrayList$SubList.get(ArrayList.java:1035)
  at com.youai.user.test.TestJava.testSubList(TestJava.java:65)
  ...
java.lang.IllegalStateException: Failed to execute ApplicationRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:759) at org.springframework.boot.SpringApplication.lambda$callRunners$2(SpringApplication.java:746) at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:498) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:487) at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:241) at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485) at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:744) at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1289) at com.zte.vd.insight.config.BootstrapApp.main(BootstrapApp.java:30) Caused by: org.springframework.dao.DuplicateKeyException: ### Error updating database. Cause: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "software_dict_pkey" (seg1 149.168.43. Detail: Key (process_name, os_type)=(powerpnt.exe, 0) already exists. ### The error may exist in file [/home/dexcloud/vd-config/conf/mapping/SoftwareProcessApdb.xml] 如何捕获异常并打印日志 List<List<SoftwareProcess> > splitedList = LocalUtils.splitList(softwareProcesses, BATCH_SIZE); for(List<SoftwareProcess> subList : splitedList){ int count = softwareProcessApMapper.batchInsertSoftwareProcess(subList); log.info("---------->>>>>softwareDictMigrationFromPgToAp: Migrate {} data's from PG to AP", count); }
03-25
package com.example.kucun2.entity.data; import android.util.Log; import androidx.annotation.NonNull; import com.example.kucun2.function.MyAppFnction; import com.google.gson.Gson; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; import java.util.Set; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; /** 支持数据变更自动同步的泛型集合类 @param <T> 继承自 SynchronizableEntity 的实体类型 */ public class SynchronizedList<T extends EntityClassGrassrootsid> implements List<T> { private final List<T> list = new ArrayList<>(); private final OkHttpClient client = new OkHttpClient(); private static final Gson gson = new Gson(); private static final MediaType JSON = MediaType.get(“application/json; charset=utf-8”); private final Class<T> entityClass; // 类型标记 // 添加批量操作模式标志 private boolean batchMode = false; // 属性变更监听器 private final List<PropertyChangeListener<T>> listeners = new ArrayList<>(); // 直接接受Class参数的构造函数 public SynchronizedList(Class<T> entityClass) { this.entityClass = entityClass; } // 安全的类型转换方法 private T safeCast(Object o) { if (o != null && entityClass.isInstance(o)) { return entityClass.cast(o); } return null; } public interface PropertyChangeListener<T> { void onPropertyChange(T entity, String propertyName, Object oldValue, Object newValue); } public void addPropertyChangeListener(PropertyChangeListener<T> listener) { listeners.add(listener); } public void removePropertyChangeListener(PropertyChangeListener<T> listener) { listeners.remove(listener); } // 添加方法来获取原始对象 @SuppressWarnings(“unchecked”) public T getOriginal(T proxy) { if (proxy == null) return null; // 检查是否为代理对象 if (java.lang.reflect.Proxy.isProxyClass(proxy.getClass())) { try { java.lang.reflect.InvocationHandler handler = java.lang.reflect.Proxy.getInvocationHandler(proxy); if (handler instanceof IProxyHandler) { Object original = ((IProxyHandler) handler).getOriginal(); // 安全类型检查 if (entityClass.isInstance(original)) { return (T) original; } } } catch (Exception e) { Log.e("SynchronizedList", "Failed to get proxy handler", e); } } return proxy; } private String url=“”; /** 同步实体到后端 @param entity 要同步的实体 */ private void syncEntity(T entity) { if (batchMode) return; String operation = “add”; T originalEntity = getOriginal(entity); String endpoint = originalEntity.getEndpoint(operation); String json = gson.toJson(originalEntity); url= MyAppFnction.getStringResource(“string”,“url”); Log.d(“getEndpoint”, "endpoint: "+endpoint); RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder() .url(url+endpoint) .method(getHttpMethod(operation), body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { Log.e(“SynchronizedList”, "同步失败: " + entity.getClass().getSimpleName(), e); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) { if (!response.isSuccessful()) { Log.e("SynchronizedList", "同步失败: " + response.code() + " - " + response.message()); } response.close(); } }); } // 添加用于批量操作的方法 public void beginBatch() { this.batchMode = true; } public void endBatch() { this.batchMode = false; // 批量结束后触发一次全量同步 syncAllEntities(); } private void syncAllEntities() { for (T entity : list) { syncEntity(entity); } } private String getHttpMethod(String operation) { switch (operation) { case “add”: return “POST”; case “update”: return “PUT”; case “delete”: return “DELETE”; default: return “POST”; } } // 获取类实现的所有接口(包括父类接口) private Class<?>[] getInterfaces(Class<?> clazz) { Set<Class<?>> interfaces = new HashSet<>(); while (clazz != null) { interfaces.addAll(Arrays.asList(clazz.getInterfaces())); clazz = clazz.getSuperclass(); } return interfaces.toArray(new Class<?>[0]); } /** 创建代理对象,用于监听属性变更 */ // 优化 createProxy 方法 private T createProxy(T original) { if (original == null) return null; // 获取实体类实现的所有接口 Set<Class<?>> interfaces = new HashSet<>(); Class<?> clazz = original.getClass(); // 收集所有接口,包括继承链中的接口 while (clazz != null) { interfaces.addAll(Arrays.asList(clazz.getInterfaces())); clazz = clazz.getSuperclass(); } // 创建代理对象 return (T) Proxy.newProxyInstance( original.getClass().getClassLoader(), interfaces.toArray(new Class<?>[0]), new EntityProxyHandler(original) ); // if (!entityClass.isInstance(original)) { // throw new IllegalArgumentException(“Invalid entity type”); // } // // 这里使用动态代理模式监听setter方法调用 // return (T) java.lang.reflect.Proxy.newProxyInstance( // original.getClass().getClassLoader(), // original.getClass().getInterfaces(), // (proxy, method, args) -> { // // 只拦截setter方法 // if (method.getName().startsWith(“set”) && args.length == 1) { // String propertyName = method.getName().substring(3); // propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); // // // 获取旧值 // Object oldValue = original.getClass() // .getMethod(“get” + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1)) // .invoke(original); // // // 调用原始方法 // Object result = method.invoke(original, args); // // // 触发监听器 // for (PropertyChangeListener<T> listener : listeners) { // listener.onPropertyChange(original, propertyName, oldValue, args[0]); // } // // // 自动同步到后端 // syncEntity(original); // return result; // } // return method.invoke(original, args); // } // ); } // 以下是List接口的实现 @Override public int size() { return list.size(); } @Override public boolean isEmpty() { return list.isEmpty(); } @Override public boolean contains(Object o) { return list.contains(o); } @NonNull @Override public Iterator<T> iterator() { return list.iterator(); } @NonNull @Override public Object[] toArray() { return list.toArray(); } @NonNull @Override public <T1> T1[] toArray(@NonNull T1[] a) { return list.toArray(a); } @Override public boolean add(T t) { T proxy = createProxy(t); boolean result = list.add(proxy); if (!batchMode) { syncEntity(proxy); } return result; // 添加时创建代理 } @Override public boolean remove(Object o) { T entity = safeCast(o); if (entity != null) { syncEntity((T) entity); // 删除前同步 } return list.remove(o); } @Override public boolean containsAll(@NonNull Collection<?> c) { return list.containsAll(c); } @Override public boolean addAll(@NonNull Collection<? extends T> c) { boolean modified = false; for (T t : c) { modified |= add(t); } return modified; } @Override public boolean addAll(int index, @NonNull Collection<? extends T> c) { for (T t : c) { add(index++, t); } return true; } @Override public boolean removeAll(@NonNull Collection<?> c) { for (Object o : c) { T entity = safeCast(o); if (entity != null) { syncEntity(entity); } } return list.removeAll(c); } @Override public boolean retainAll(@NonNull Collection<?> c) { List<T> toRemove = new ArrayList<>(); for (T t : list) { if (!c.contains(t)) { toRemove.add(t); } } // 使用安全转换 for (T entity : toRemove) { syncEntity(entity); } return list.retainAll(c); } @Override public void clear() { for (T t : list) { syncEntity(t); // 清空前同步 } list.clear(); } @Override public T get(int index) { return list.get(index); } @Override public T set(int index, T element) { T old = list.set(index, createProxy(element)); if (old != null) { syncEntity(old); // 替换旧元素前同步 } return old; } @Override public void add(int index, T element) { list.add(index, createProxy(element)); } @Override public T remove(int index) { T removed = list.remove(index); if (removed != null) { syncEntity(removed); // 删除前同步 } return removed; } @Override public int indexOf(Object o) { return list.indexOf(o); } @Override public int lastIndexOf(Object o) { return list.lastIndexOf(o); } @NonNull @Override public ListIterator<T> listIterator() { return list.listIterator(); } @NonNull @Override public ListIterator<T> listIterator(int index) { return list.listIterator(index); } @NonNull @Override public List<T> subList(int fromIndex, int toIndex) { return list.subList(fromIndex, toIndex); } // 触发属性变更通知 // 添加类型安全的属性监听 private void firePropertyChange(T entity, String propertyName, Object oldValue, Object newValue) { if (oldValue != null && newValue != null && oldValue.equals(newValue)) { return; // 值未变化时不触发监听 } for (PropertyChangeListener<T> listener : listeners) { try { listener.onPropertyChange(entity, propertyName, oldValue, newValue); } catch (Exception e) { Log.e("SynchronizedList", "Listener error", e); } } } // 修改代理处理器以支持获取原始对象 /* 完整的 EntityProxyHandler 实现 */ private class EntityProxyHandler implements IProxyHandler, java.lang.reflect.InvocationHandler { private final T original; private final Map<String, Object> propertyValues = new HashMap<>(); public EntityProxyHandler(T original) { this.original = original; cachePropertyValues(); } private void cachePropertyValues() { // 获取类信息 Class<?> clazz = original.getClass(); // 遍历所有getter方法 for (Method method : clazz.getMethods()) { String methodName = method.getName(); // 只处理getter方法 if (methodName.startsWith("get") && !methodName.equals("getClass") && method.getParameterTypes().length == 0) { try { // 获取属性名(去掉"get"并将首字母小写) String propertyName = methodName.substring(3); propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1); // 调用getter获取值 Object value = method.invoke(original); propertyValues.put(propertyName, value); } catch (Exception e) { Log.e("Wrapper", "Failed to cache property " + methodName, e); } } } } @Override public T getOriginal() { return original; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); // 只拦截setter方法 if (methodName.startsWith("set") && args != null && args.length == 1) { String propertyName = methodName.substring(3); propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1); Object oldValue = propertyValues.get(propertyName); Object newValue = args[0]; // 如果值未改变,不触发同步 if (Objects.equals(oldValue, newValue)) { return null; } // 调用原始对象的setter方法 Method setter = original.getClass().getMethod(methodName, newValue.getClass()); setter.invoke(original, newValue); // 更新属性缓存 propertyValues.put(propertyName, newValue); // 触发属性变更监听 firePropertyChange(original, propertyName, oldValue, newValue); // 非批量模式下自动同步 if (!batchMode) { syncEntity(original); } } // 其他接口方法直接调用原始对象 return method.invoke(original, args); } private Object getPropertyValue(String propertyName) { String getterName = "get" + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); try { Method getter = original.getClass().getMethod(getterName); return getter.invoke(original); } catch (Exception e) { Log.e("ProxyHandler", "Failed to get property value: " + propertyName, e); return null; } } } // 在 SynchronizedList 类中添加 public interface IProxyHandler { Object getOriginal(); } }package com.example.kucun2.entity.data; import android.util.Log; import com.example.kucun2.function.MyAppFnction; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.HashMap; import java.util.Map; public abstract class SynchronizableEntity implements EntityClassGrassrootsid { // 使用标准属性变更支持类 private transient PropertyChangeSupport changeSupport = new PropertyChangeSupport(this); // 属性缓存(可选,用于优化) private final Map<String, Object> propertyCache = new HashMap<>(); // 添加属性变更监听器 public void addPropertyChangeListener(PropertyChangeListener listener) { if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } changeSupport.addPropertyChangeListener(listener); } // 移除属性变更监听器 public void removePropertyChangeListener(PropertyChangeListener listener) { if (changeSupport != null) { changeSupport.removePropertyChangeListener(listener); } } // 触发属性变更通知(子类在setter中调用) protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { if (changeSupport != null && changeSupport.hasListeners(propertyName)) { // 更新属性缓存(可选) propertyCache.put(propertyName, newValue); // 触发变更事件 changeSupport.firePropertyChange(propertyName, oldValue, newValue); } } // 获取属性当前值(可选,用于setter中获取旧值) protected <T> T getCachedProperty(String propertyName) { return (T) propertyCache.get(propertyName); } // 初始化属性缓存(可选,在构造函数中调用) protected void initPropertyCache() { // 初始化所有字段到缓存 for (java.lang.reflect.Field field : getClass().getDeclaredFields()) { try { field.setAccessible(true); propertyCache.put(field.getName(), field.get(this)); } catch (Exception e) { // 忽略初始化异常 } } } /** * 添加url * @param type 操作增删改查 * @return 返回相对url */ public String getEndpoint(String type){ //从String.xml获取url Log.d("getEndpoint", "getEndpoint: "+"url_"+type+"_"+this.getClass().getSimpleName().toLowerCase()); return MyAppFnction.getStringResource("string","url_"+type+"_"+this.getClass().getSimpleName().toLowerCase()); } public void sync(){ } } package com.example.kucun2.entity; import com.example.kucun2.entity.data.EntityClassGrassrootsid; import com.example.kucun2.entity.data.SynchronizableEntity; import java.util.ArrayList; import java.util.Date; import java.util.List; /** 订单 */ public class Dingdan extends SynchronizableEntity implements EntityClassGrassrootsid { private Integer id; private String number; private List<Dingdan_Chanpin> chanpins; private Date xiadan; private Date jiaohuo; public Dingdan(Integer id, String number, List<Dingdan_Chanpin> chanpins, Date xiadan, Date jiaohuo) { this.id = id; this.number = number; this.chanpins = chanpins; this.xiadan = xiadan; this.jiaohuo = jiaohuo; } @Override public Integer getId() { return id; } public void setId(Integer id) { Integer oldValue = this.id; this.id = id; firePropertyChange(“id”, oldValue, id); } public String getNumber() { return number; } public void setNumber(String number) { String oldValue = this.number; this.number = number; firePropertyChange(“number”, oldValue, number); } public List<Dingdan_Chanpin> getChanpins() { return chanpins; } public void setChanpins(List<Dingdan_Chanpin> chanpins) { List<Dingdan_Chanpin> oldValue = this.chanpins; this.chanpins = chanpins; firePropertyChange(“chanpins”, oldValue, chanpins); } public Date getXiadan() { return xiadan; } public void setXiadan(Date xiadan) { Date oldValue = this.xiadan; this.xiadan = xiadan; firePropertyChange(“xiadan”, oldValue, xiadan); } public Date getJiaohuo() { return jiaohuo; } public void setJiaohuo(Date jiaohuo) { Date oldValue = this.jiaohuo; this.jiaohuo = jiaohuo; firePropertyChange(“jiaohuo”, oldValue, jiaohuo); } public Dingdan() { } }已在SynchronizableEntity中设置了监听,取消代理
最新发布
06-11
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值