方便创建容器对象的工具CollectionUtil

本文介绍了一个实用的集合操作工具类,提供了创建各种类型的集合、检查集合是否为空、从集合中提取属性形成新的集合或映射、转换集合元素为字符串等功能。通过这个工具类,可以简化集合操作,提高代码的可读性和维护性。
public final class CollectionUtil {

    /**
     * 创建一个<code>ArrayList</code>。
     */
    public static <T> ArrayList<T> createArrayList() {
        return new ArrayList<T>();
    }

    /**
     * 创建一个<code>ArrayList</code>。
     */
    public static <T> ArrayList<T> createArrayList(int initialCapacity) {
        return new ArrayList<T>(initialCapacity);
    }

    /**
     * 创建一个<code>ArrayList</code>。
     */
    public static <T> ArrayList<T> createArrayList(Iterable<? extends T> c) {
        ArrayList<T> list;

        if (c instanceof Collection<?>) {
            list = new ArrayList<T>((Collection<? extends T>) c);
        } else {
            list = new ArrayList<T>();

            iterableToCollection(c, list);

            list.trimToSize();
        }

        return list;
    }

    /**
     * 创建一个<code>ArrayList</code>。
     */
    public static <T, V extends T> ArrayList<T> createArrayList(V... args) {
        if (args == null || args.length == 0) {
            return new ArrayList<T>();
        } else {
            ArrayList<T> list = new ArrayList<T>(args.length);

            for (V v : args) {
                list.add(v);
            }

            return list;
        }
    }

    /**
     * 创建一个<code>LinkedList</code>。
     */
    public static <T> LinkedList<T> createLinkedList() {
        return new LinkedList<T>();
    }

    /**
     * 创建一个<code>LinkedList</code>。
     */
    public static <T> LinkedList<T> createLinkedList(Iterable<? extends T> c) {
        LinkedList<T> list = new LinkedList<T>();

        iterableToCollection(c, list);

        return list;
    }

    /**
     * 创建一个<code>LinkedList</code>。
     */
    public static <T, V extends T> LinkedList<T> createLinkedList(V... args) {
        LinkedList<T> list = new LinkedList<T>();

        if (args != null) {
            for (V v : args) {
                list.add(v);
            }
        }

        return list;
    }

    /**
     * 创建一个<code>List</code>。
     * <p>
     * 和{@code createArrayList(args)}不同,本方法会返回一个不可变长度的列表,且性能高于
     * {@code createArrayList(args)}。
     * </p>
     */
    public static <T> List<T> asList(T... args) {
        if (args == null || args.length == 0) {
            return Collections.emptyList();
        } else {
            return Arrays.asList(args);
        }
    }

    /**
     * 创建一个<code>HashMap</code>。
     */
    public static <K, V> HashMap<K, V> createHashMap() {
        return new HashMap<K, V>();
    }

    /**
     * 创建一个<code>HashMap</code>。
     */
    public static <K, V> HashMap<K, V> createHashMap(int initialCapacity) {
        return new HashMap<K, V>(initialCapacity);
    }

    /**
     * 创建一个<code>LinkedHashMap</code>。
     */
    public static <K, V> LinkedHashMap<K, V> createLinkedHashMap() {
        return new LinkedHashMap<K, V>();
    }

    /**
     * 创建一个<code>LinkedHashMap</code>。
     */
    public static <K, V> LinkedHashMap<K, V> createLinkedHashMap(int initialCapacity) {
        return new LinkedHashMap<K, V>(initialCapacity);
    }

    /**
     * 创建一个<code>TreeMap</code>。
     */
    public static <K, V> TreeMap<K, V> createTreeMap() {
        return new TreeMap<K, V>();
    }

    /**
     * 创建一个<code>TreeMap</code>。
     */
    public static <K, V> TreeMap<K, V> createTreeMap(Comparator<? super K> comparator) {
        return new TreeMap<K, V>(comparator);
    }

    /**
     * 创建一个<code>ConcurrentHashMap</code>。
     */
    public static <K, V> ConcurrentHashMap<K, V> createConcurrentHashMap() {
        return new ConcurrentHashMap<K, V>();
    }

    /**
     * 创建一个<code>HashSet</code>。
     */
    public static <T> HashSet<T> createHashSet() {
        return new HashSet<T>();
    }

    /**
     * 创建一个<code>HashSet</code>。
     */
    public static <T, V extends T> HashSet<T> createHashSet(V... args) {
        if (args == null || args.length == 0) {
            return new HashSet<T>();
        } else {
            HashSet<T> set = new HashSet<T>(args.length);

            for (V v : args) {
                set.add(v);
            }

            return set;
        }
    }

    /**
     * 创建一个<code>HashSet</code>。
     */
    public static <T> HashSet<T> createHashSet(Iterable<? extends T> c) {
        HashSet<T> set;

        if (c instanceof Collection<?>) {
            set = new HashSet<T>((Collection<? extends T>) c);
        } else {
            set = new HashSet<T>();
            iterableToCollection(c, set);
        }

        return set;
    }

    /**
     * 创建一个<code>LinkedHashSet</code>。
     */
    public static <T> LinkedHashSet<T> createLinkedHashSet() {
        return new LinkedHashSet<T>();
    }

    /**
     * 创建一个<code>LinkedHashSet</code>。
     */
    public static <T, V extends T> LinkedHashSet<T> createLinkedHashSet(V... args) {
        if (args == null || args.length == 0) {
            return new LinkedHashSet<T>();
        } else {
            LinkedHashSet<T> set = new LinkedHashSet<T>(args.length);

            for (V v : args) {
                set.add(v);
            }

            return set;
        }
    }

    /**
     * 创建一个<code>LinkedHashSet</code>。
     */
    public static <T> LinkedHashSet<T> createLinkedHashSet(Iterable<? extends T> c) {
        LinkedHashSet<T> set;

        if (c instanceof Collection<?>) {
            set = new LinkedHashSet<T>((Collection<? extends T>) c);
        } else {
            set = new LinkedHashSet<T>();
            iterableToCollection(c, set);
        }

        return set;
    }

    /**
     * 创建一个<code>TreeSet</code>。
     */
    public static <T> TreeSet<T> createTreeSet() {
        return new TreeSet<T>();
    }

    /**
     * 创建一个<code>TreeSet</code>。
     */
    @SuppressWarnings("unchecked")
    public static <T, V extends T> TreeSet<T> createTreeSet(V... args) {
        return (TreeSet<T>) createTreeSet(null, args);
    }

    /**
     * 创建一个<code>TreeSet</code>。
     */
    public static <T> TreeSet<T> createTreeSet(Iterable<? extends T> c) {
        return createTreeSet(null, c);
    }

    /**
     * 创建一个<code>TreeSet</code>。
     */
    public static <T> TreeSet<T> createTreeSet(Comparator<? super T> comparator) {
        return new TreeSet<T>(comparator);
    }

    /**
     * 创建一个<code>TreeSet</code>。
     */
    public static <T, V extends T> TreeSet<T> createTreeSet(Comparator<? super T> comparator, V... args) {
        TreeSet<T> set = new TreeSet<T>(comparator);

        if (args != null) {
            for (V v : args) {
                set.add(v);
            }
        }

        return set;
    }

    /**
     * 创建一个<code>TreeSet</code>。
     */
    public static <T> TreeSet<T> createTreeSet(Comparator<? super T> comparator, Iterable<? extends T> c) {
        TreeSet<T> set = new TreeSet<T>(comparator);

        iterableToCollection(c, set);

        return set;
    }


    private static <T> void iterableToCollection(Iterable<? extends T> c, Collection<T> list) {
        for (T element : c) {
            list.add(element);
        }
    }

    /**
     * Return <code>true</code> if the supplied Collection is <code>null</code>
     * or empty. Otherwise, return <code>false</code>.
     *
     * @param collection the Collection to check
     * @return whether the given Collection is empty
     */
    public static boolean isEmpty(Collection collection) {
        return (collection == null || collection.isEmpty());
    }

    /**
     * Return <code>false</code> if the supplied Collection is <code>null</code>
     * or empty. Otherwise, return <code>true</code>.
     *
     * @param collection the Collection to check
     * @return whether the given Collection is not empty
     */
    public static boolean isNotEmpty(Collection collection) {
        return !isEmpty(collection);
    }

    /**
     * Return <code>true</code> if the supplied Map is <code>null</code>
     * or empty. Otherwise, return <code>false</code>.
     *
     * @param map the Map to check
     * @return whether the given Map is empty
     */
    public static boolean isEmpty(Map map) {
        return (map == null || map.isEmpty());
    }

    public static String[] toNoNullStringArray(Collection collection) {
        if (collection == null) {
            return ArrayUtils.EMPTY_STRING_ARRAY;
        }
        return toNoNullStringArray(collection.toArray());
    }

    static String[] toNoNullStringArray(Object[] array) {
        ArrayList list = new ArrayList(array.length);
        for (int i = 0; i < array.length; i++) {
            Object e = array[i];
            if (e != null) {
                list.add(e.toString());
            }
        }
        return (String[]) list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    }

    /////////////////////////////////

    /**
     * 提取集合中的对象的两个属性(通过Getter函数), 组合成Map.
     *
     * @param collection        来源集合.
     * @param keyPropertyName   要提取为Map中的Key值的属性名.
     * @param valuePropertyName 要提取为Map中的Value值的属性名.
     */
    public static Map extractToMap(final Collection collection, final String keyPropertyName,
                                   final String valuePropertyName) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Map map = new HashMap(collection.size());
        for (Object obj : collection) {
            map.put(PropertyUtils.getProperty(obj, keyPropertyName),
                    PropertyUtils.getProperty(obj, valuePropertyName));
        }
        return map;
    }

    /**
     * 提取集合中的对象的某个属性(通过Getter函数)作为key,集合对象作为值,组合成Map.
     *
     * @param collection      来源集合.
     * @param keyPropertyName 要提取为Map中的Key值的属性名.
     */
    public static <E> Map extractIndexToMap(final Collection<E> collection, final String keyPropertyName) {
        if (collection == null) {
            return new HashMap();
        }
        Map map = new HashMap(collection.size());
        for (E obj : collection) {
            if (obj == null) {
                continue;
            }
            try {
                map.put(PropertyUtils.getProperty(obj, keyPropertyName), obj);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
        return map;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成List.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public static List extractToList(final Collection collection, final String propertyName) {
        if (collection == null) {
            return new ArrayList();
        }
        List list = new ArrayList(collection.size());
        for (Object obj : collection) {
            if (obj == null) {
                continue;
            }
            try {
                list.add(PropertyUtils.getProperty(obj, propertyName));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }

        return list;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成由分割符分隔的字符串.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     * @param separator    分隔符.
     * @return
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     */
    public static String extractToString(final Collection collection, final String propertyName, final String separator) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        List list = extractToList(collection, propertyName);
        return StringUtils.join(list, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 中间以 separator分隔。
     *
     * @param collection
     * @param separator
     * @return
     */
    public static String convertToString(final Collection collection, final String separator) {
        return StringUtils.join(collection, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 每个元素的前面加入prefix,后面加入postfix,如<div>mymessage</div>。
     *
     * @param collection
     * @param prefix
     * @param postfix
     * @return
     */
    public static String convertToString(final Collection collection, final String prefix, final String postfix) {
        StringBuilder builder = new StringBuilder();
        for (Object o : collection) {
            builder.append(prefix).append(o).append(postfix);
        }
        return builder.toString();
    }


    /**
     * 取得Collection的第一个元素,如果collection为空返回null.
     *
     * @param collection
     * @param <T>
     * @return
     */
    public static <T> T getFirst(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        return collection.iterator().next();
    }

    /**
     * 获取Collection的最后一个元素 ,如果collection为空返回null.
     *
     * @param collection
     * @param <T>
     * @return
     */
    public static <T> T getLast(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }

        //当类型为List时,直接取得最后一个元素 。
        if (collection instanceof List) {
            List<T> list = (List<T>) collection;
            return list.get(list.size() - 1);
        }

        //其他类型通过iterator滚动到最后一个元素.
        Iterator<T> iterator = collection.iterator();
        while (true) {
            T current = iterator.next();
            if (!iterator.hasNext()) {
                return current;
            }
        }
    }

    /**
     * 返回a+b的新List.
     *
     * @param a
     * @param b
     * @param <T>
     * @return
     */
    public static <T> List<T> union(final Collection<T> a, final Collection<T> b) {
        List<T> result = new ArrayList<T>(a);
        result.addAll(b);
        return result;
    }

    /**
     * 返回a-b的新List.
     *
     * @param a
     * @param b
     * @param <T>
     * @return
     */
    public static <T> List<T> subtract(final Collection<T> a, final Collection<T> b) {
        List<T> list = new ArrayList<T>(a);
        for (T element : b) {
            list.remove(element);
        }
        return list;
    }

    /**
     * 返回a与b的交集的新List.
     *
     * @param a
     * @param b
     * @param <T>
     * @return
     */
    public static <T> List<T> intersection(Collection<T> a, Collection<T> b) {
        List<T> list = new ArrayList<T>();

        for (T element : a) {
            if (b.contains(element)) {
                list.add(element);
            }
        }
        return list;
    }

}
分析下面代码,参考saveGoodsInfo函数,实现saveGoodsBatch函数 @Override @Transactional(rollbackFor = Exception.class) public void saveGoodsBatch(GoodsInfoDTO.ExcelGoodsDataETO eto) { } @Override @Transactional(rollbackFor = Exception.class) public void saveGoodsInfo(GoodsInfoDTO.ETO eto) { valicateGoodsNo(eto); GoodsInfo goodsInfo = CommodityStructMapper.INSTANCE.goodsData2PO(eto); if (GoodsEntryChannelEnum.MERCH.getCode().equals(eto.getDataEntryChannel())) { goodsInfo.setGoodsState(GoodsStateEnum.INIT.getCode()); goodsInfo.setCheckState(ApplyCheckStateEnum.WAITING.getCode()); } else { goodsInfo.setCheckState(ApplyCheckStateEnum.PASS.getCode()); goodsInfo.setGoodsState(GoodsStateEnum.DOWN.getCode()); } goodsInfo.setCheckTime(DateUtils.nowTime()); boolean flag = goodsInfoRepository.saveOrUpdate(goodsInfo); if (!flag) { throw new BusinessException(MsgCodeCommodityEnum.INFO_BIZ_ERROR_SAVE_FAIL.getMsgUniqueCode(), MsgCodeCommodityEnum.INFO_BIZ_ERROR_SAVE_FAIL.getMsgUniqueMsgKey()); } List<GoodsInfoDTO.SkuItem> newSkuItemList = eto.getSkuItemList(); initGoodsSkuPriceInfoForMerchEdit(eto.getDataEntryChannel(), goodsInfo.getShopId(), newSkuItemList, goodsInfo.getId()); //扩展参数属性删除:属性/参数/规格/diyTab/sku goodsExpendService.deleteExtendData(goodsInfo.getId()); //参数/属性/规格/DIYTab数据添加 goodsExpendService.saveGoodsRelationExtendGroupKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.ATTR.getCode(), eto.getAttrItemList()); goodsExpendService.saveGoodsRelationExtendGroupKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.PARAM.getCode(), eto.getParamItemList()); goodsExpendService.saveGoodsRelationExtendGroupKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.SPEC.getCode(), eto.getSpecItemList()); goodsExpendService.saveGoodsRelationExtendGroupKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.DIY_TAB.getCode(), eto.getDiyTabList()); //标签|渠道保存 goodsExpendService.saveGoodsRelationExtendItemKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.LABEL.getCode(), eto.getGoodsLabelList()); goodsExpendService.saveGoodsRelationExtendItemKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.CHANNEL.getCode(), eto.getGoodsChannelList()); //系列保存 goodsExpendService.saveGoodsRelationExtendItemKeyValue(goodsInfo.getId(), GoodsExtendBizTypeEnum.SERIES.getCode(), eto.getGoodsSeriesList()); //商品基础扩展保存 goodsExpendService.saveGoodsInfoExtend(goodsInfo.getId(), eto); //sku明细保存 goodsExpendService.saveSku(goodsInfo, newSkuItemList); //todo 更改原先ERP接口为金蝶接口 thirdOpenGoodsService.syncJdGoods(null,null, Lists.newArrayList(goodsInfo.getId())); esGoodsIndexService.edit(goodsInfo.getId()); //处理商品交期关联商品 siteConfigRpc.updateSysDictItemCount(Arrays.asList(eto.getPreSendTime()), SysNumberConst.P1); } /** * 设置商品的价格信息 * * @param targetList * @param goodsId */ private void initGoodsSkuPriceInfoForMerchEdit(Integer dataEntryChannel, String shopId, List<GoodsInfoDTO.SkuItem> targetList, String goodsId) { if (StrUtil.isEmpty(goodsId)) { return; } List<GoodsRelationDataPrice> goodsSkuPriceList = goodsExpendService.listGoodsPrice(goodsId, null); //未设置价格 if (CollectionUtil.isEmpty(goodsSkuPriceList)) { return; } boolean merchFlag = GoodsEntryChannelEnum.MERCH.getCode().equals(dataEntryChannel); Map<String, GoodsRelationDataPrice> existsSkuPriceMap = goodsSkuPriceList.stream().collect(Collectors.toMap(GoodsRelationDataPrice::getSkuId, item -> item, (item1, item2) -> item1)); //商家调整数据-只允许修改结算价格 for (GoodsInfoDTO.SkuItem item : targetList) { //原来没有价格或者是系统商户(平台/商家端 可以变更所有价格字段) if (!existsSkuPriceMap.containsKey(item.getSkuNo()) || SysMerchConst.SHOP_ID.equals(shopId)) { continue; } GoodsInfoDTO.GoodsPrice existSkuPrice = CommodityStructMapper.INSTANCE.skuPriceData2DTO(existsSkuPriceMap.get(item.getSkuNo())); if (merchFlag) { existSkuPrice.setSupplierSettlePrice(item.getGoodsPrice().getSupplierSettlePrice()); existSkuPrice.setOldPrice(item.getGoodsPrice().getOldPrice()); item.setGoodsPrice(existSkuPrice); continue; } if (ObjectUtil.isNotNull(existSkuPrice.getSupplierSettlePrice())) { item.getGoodsPrice().setSupplierSettlePrice(existSkuPrice.getSupplierSettlePrice()); } if (ObjectUtil.isNull(item.getGoodsPrice().getSupplierSettlePrice())) { item.getGoodsPrice().setSupplierSettlePrice(item.getGoodsPrice().getSalePrice()); } item.getGoodsPrice().setOldPrice(existSkuPrice.getOldPrice()); } } /** * 商品编号校验 * * @param eto */ private void valicateGoodsNo(GoodsInfoDTO.ETO eto) { Boolean valicateGoodsNoFlag = Boolean.TRUE; Boolean addGoodsFlag = StrUtil.isEmpty(eto.getId()); if (StrUtil.isEmpty(eto.getGoodsNo())) { eto.setGoodsNo(OrderNoUtil.getGoodsNo()); valicateGoodsNoFlag = Boolean.FALSE; } if (StrUtil.isEmpty(eto.getShopId())) { eto.setShopId(SysMerchConst.SHOP_ID); } //获取店铺数据 if (StrUtil.isEmpty(eto.getMerchantId())) { eto.setMerchantId(SysMerchConst.MERCH_ID); } if (StrUtil.isEmpty(eto.getSplitCode())) { eto.setSplitCode(eto.getShopId()); eto.setSplitName(eto.getShopName()); } Boolean singleFlag = EnUnStateEnum.ENABLE.getCode().equals(eto.getIsSingle()); int idx = SysNumberConst.P1.intValue(); Boolean valicateGoodsSkuNoFlag = Boolean.TRUE; List<String> skuNoList = new ArrayList<>(); List<String> skuNoExistList = eto.getSkuItemList().stream().filter(item -> StrUtil.isNotEmpty(item.getSkuNo())).map(GoodsInfoDTO.SkuItem::getSkuNo).collect(toList()); if (CollectionUtil.isEmpty(eto.getSkuItemList())) { valicateGoodsSkuNoFlag = Boolean.FALSE; } for (GoodsInfoDTO.SkuItem skuItem : eto.getSkuItemList()) { if (StrUtil.isEmpty(skuItem.getSkuNo())) { GoodsInfoDTO.GoodsSkuNoInit skuNoObj = installSkuNo(singleFlag, eto.getGoodsNo(), idx, skuNoExistList); idx = skuNoObj.getSkuIdx(); skuItem.setSkuNo(skuNoObj.getGoodsSkuNo()); valicateGoodsSkuNoFlag = Boolean.FALSE; } if (skuNoList.contains(skuItem.getSkuNo())) { throw new BusinessException(MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueCode(), MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueMsgKey(), new Object[]{skuItem.getSkuNo()}); } skuNoList.add(skuItem.getSkuNo()); } if (valicateGoodsNoFlag) { // 增加根据编号和供应商ID查询商品 List<GoodsInfo> goodsList = listGoodsMerchInfoByGoodsNo(null, eto.getGoodsNo(),eto.getMerchantId()); if (CollectionUtil.isNotEmpty(goodsList)) { if (addGoodsFlag) { throw new BusinessException(MsgCodeCommodityEnum.INFO_BIZ_ERROR_CODE_EXISTS.getMsgUniqueCode(), MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueMsgKey(), new Object[]{JSONUtil.toJsonStr(goodsList.stream().map(GoodsInfo::getGoodsNo).distinct().collect(toList()))}); } List<GoodsInfo> goodsFilterList = goodsList.stream().filter(item -> !item.getId().equals(eto.getId())).collect(toList()); if (CollectionUtil.isNotEmpty(goodsFilterList)) { throw new BusinessException(MsgCodeCommodityEnum.INFO_BIZ_ERROR_CODE_EXISTS.getMsgUniqueCode(), MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueMsgKey(), new Object[]{JSONUtil.toJsonStr(goodsFilterList.stream().map(GoodsInfo::getGoodsNo).distinct().collect(toList()))}); } } } if (valicateGoodsSkuNoFlag) { List<GoodsSkuInfo> goodsSkuList = goodsExpendService.listGoodsSkuBySkuNo(skuNoList); if (CollectionUtil.isNotEmpty(goodsSkuList)) { if (addGoodsFlag) { throw new BusinessException(MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueCode(), MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueMsgKey(), new Object[]{JSONUtil.toJsonStr(goodsSkuList.stream().map(GoodsSkuInfo::getSkuNo).distinct().collect(toList()))}); } if (!eto.getId().equals(goodsSkuList.get(SysNumberConst.P0).getGoodsId())) { throw new BusinessException(MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueCode(), MsgCodeCommodityEnum.INFO_BIZ_ERROR_SKU_EXISTS.getMsgUniqueMsgKey(), new Object[]{JSONUtil.toJsonStr(goodsSkuList.stream().map(GoodsSkuInfo::getSkuNo).distinct().collect(toList()))}); } } } } /** * 生成sku编号 * * @param singleFlag * @param goodsNo * @param idx * @param skuNoExistList * @return */ private GoodsInfoDTO.GoodsSkuNoInit installSkuNo(Boolean singleFlag, String goodsNo, Integer idx, List<String> skuNoExistList) { GoodsInfoDTO.GoodsSkuNoInit retObj = new GoodsInfoDTO.GoodsSkuNoInit(); if (singleFlag) { retObj.setSkuIdx(idx); retObj.setGoodsSkuNo(goodsNo); return retObj; } while (true) { String skuNoTmp = createGoodsSkuNo(idx, goodsNo, skuNoExistList); idx++; if (StrUtil.isNotEmpty(skuNoTmp)) { retObj.setSkuIdx(idx); retObj.setGoodsSkuNo(skuNoTmp); return retObj; } } } /** * 生成单号 * * @param idx * @param goodsNo * @param existSkuNoList * @return */ private String createGoodsSkuNo(Integer idx, String goodsNo, List<String> existSkuNoList) { String skuNoTmp = goodsNo.concat(SysSplitConst.MALL_STRIGULA_SPLIT).concat(idx.toString()); if (CollectionUtil.isEmpty(existSkuNoList) || !existSkuNoList.contains(skuNoTmp)) { return skuNoTmp; } return SysSplitConst.BlankStr; }
07-22
package com.hangcheng.website.util; import cn.hutool.core.collection.CollectionUtil; import com.hangcheng.website.config.CourseConfig; import com.hangcheng.website.domain.response.ComboResult; import com.hangcheng.website.domain.response.ComboVoResult; import com.hangcheng.website.domain.response.CourseIntelligentPageResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.*; import java.util.stream.Collectors; /** * @ClassName : CourseSelectUtils * @Description : 课程智能组合工具类 - 针对200课程10组合优化版 * @Author : 牛欣如 * @Date: 2025-09-02 14:10 */ @Component public class CourseSelectUtils { @Autowired private CourseConfig courseConfig; private static final int MAX_COURSES_PER_COMBO = 10; private static final int MAX_COMBINATIONS_PER_GROUP = 10; private static final int MAX_TOTAL_COURSES = 200; /** * 为单个条件生成课程组合(优化版,专门针对200课程生成10个组合) */ public List<List<CourseIntelligentPageResponse>> generateNearestCombinations( int targetHours, int minCourses, int maxCourses, List<CourseIntelligentPageResponse> courses, int numCombinations) { // 过滤有效课程并排序(按学时降序,利于剪枝) List<CourseIntelligentPageResponse> validCourses = courses.stream() .limit(MAX_TOTAL_COURSES).collect(Collectors.toList()); // 根据数据规模选择合适的算法 List<List<CourseIntelligentPageResponse>> combinations; combinations = findCombinationsBacktrackOptimized(validCourses, targetHours, minCourses, maxCourses, numCombinations); // 排序:门数升序,相同时学时降序 combinations.sort((c1, c2) -> { int sizeCompare = Integer.compare(c1.size(), c2.size()); if (sizeCompare != 0) return sizeCompare; int sum1 = c1.stream().mapToInt(CourseIntelligentPageResponse::getHourCount).sum(); int sum2 = c2.stream().mapToInt(CourseIntelligentPageResponse::getHourCount).sum(); return Integer.compare(sum2, sum1); }); return getUniqueCombinations(combinations, numCombinations); } /** * 优化的回溯算法 */ private List<List<CourseIntelligentPageResponse>> findCombinationsBacktrackOptimized( List<CourseIntelligentPageResponse> courses, int targetHours, int minCourses, int maxCourses, int maxResults) { List<List<CourseIntelligentPageResponse>> result = new ArrayList<>(); Set<String> fingerprints = new HashSet<>(); // 按门数范围分别搜索 for (int courseCount = minCourses; courseCount <= maxCourses && result.size() < maxResults; courseCount++) { backtrackOptimized(courses, targetHours, courseCount, 0, new ArrayList<>(), result, fingerprints, maxResults); } return result; } /** * 强化的回溯剪枝算法 */ private void backtrackOptimized(List<CourseIntelligentPageResponse> courses, int target, int courseCount, int start, List<CourseIntelligentPageResponse> current, List<List<CourseIntelligentPageResponse>> result, Set<String> fingerprints, int maxResults) { if (result.size() >= maxResults) return; // 提前终止条件:当前总和已经超过目标 int currentSum = current.stream().mapToInt(CourseIntelligentPageResponse::getHourCount).sum(); if (currentSum > target) return; if (current.size() == courseCount) { if (currentSum == target) { String fingerprint = generateCombinationFingerprint(current); if (!fingerprints.contains(fingerprint)) { fingerprints.add(fingerprint); result.add(new ArrayList<>(current)); } } return; } // 计算剩余课程的最大可能和 int maxRemainingSum = 0; int remainingCourses = courseCount - current.size(); for (int i = start; i < Math.min(start + remainingCourses, courses.size()); i++) { maxRemainingSum += courses.get(i).getHourCount(); } // 强力剪枝 if (currentSum + maxRemainingSum < target) return; for (int i = start; i < courses.size() && result.size() < maxResults; i++) { CourseIntelligentPageResponse course = courses.get(i); // 剪枝:加上当前课程后超过目标 if (currentSum + course.getHourCount() > target) continue; // 剪枝:剩余位置不足 if (courses.size() - i < courseCount - current.size()) break; current.add(course); backtrackOptimized(courses, target, courseCount, i + 1, current, result, fingerprints, maxResults); current.remove(current.size() - 1); } } /** * 跨条件组合生成(优化版) */ public ComboVoResult generateOrderedCombinations( Map<String, List<List<CourseIntelligentPageResponse>>> groupCombinationsMap, int numCombinations) { ComboVoResult voResult = new ComboVoResult(); if (CollectionUtil.isEmpty(groupCombinationsMap)) { voResult.setResults(new ArrayList<>()); voResult.setFailGroupCourses(new ArrayList<>()); return voResult; } // 验证每个条件的组合数量 List<String> failGroups = groupCombinationsMap.entrySet().stream() .filter(entry -> CollectionUtil.isEmpty(entry.getValue())) .map(Map.Entry::getKey) .collect(Collectors.toList()); if (!failGroups.isEmpty()) { voResult.setResults(new ArrayList<>()); voResult.setFailGroupCourses(failGroups); return voResult; } // 限制每个条件的组合数量,避免组合爆炸 Map<String, List<List<CourseIntelligentPageResponse>>> limitedCombinationsMap = new HashMap<>(); groupCombinationsMap.forEach((key, combinations) -> { List<List<CourseIntelligentPageResponse>> limited = combinations.stream() .limit(MAX_COMBINATIONS_PER_GROUP) .collect(Collectors.toList()); limitedCombinationsMap.put(key, limited); }); // 使用DFS生成跨条件组合 List<ComboResult> results = generateCrossGroupCombinationsDFS(limitedCombinationsMap, numCombinations); voResult.setResults(results); voResult.setFailGroupCourses(new ArrayList<>()); // 前面已经验证过,没有失败组 return voResult; } /** * 使用DFS生成跨条件组合(避免重复课程) */ private List<ComboResult> generateCrossGroupCombinationsDFS( Map<String, List<List<CourseIntelligentPageResponse>>> groupCombinationsMap, int maxCombinations) { List<ComboResult> results = new ArrayList<>(); List<String> groupKeys = new ArrayList<>(groupCombinationsMap.keySet()); // 按组合数量升序排列,优先处理组合少的组(利于剪枝) groupKeys.sort((k1, k2) -> Integer.compare(groupCombinationsMap.get(k1).size(), groupCombinationsMap.get(k2).size())); dfsCrossGroups(groupCombinationsMap, groupKeys, 0, new LinkedHashMap<>(), new HashSet<>(), results, maxCombinations); return results; } /** * DFS递归生成跨组组合 */ private void dfsCrossGroups(Map<String, List<List<CourseIntelligentPageResponse>>> groupCombinationsMap, List<String> groupKeys, int currentIndex, Map<String, List<CourseIntelligentPageResponse>> currentSelection, Set<Long> usedCourseIds, List<ComboResult> results, int maxResults) { if (results.size() >= maxResults) return; if (currentIndex >= groupKeys.size()) { // 找到一个完整组合 ComboResult combo = new ComboResult(); combo.setGroupCourses(new LinkedHashMap<>(currentSelection)); results.add(combo); return; } String currentGroup = groupKeys.get(currentIndex); List<List<CourseIntelligentPageResponse>> combinations = groupCombinationsMap.get(currentGroup); for (List<CourseIntelligentPageResponse> combination : combinations) { // 检查课程是否重复 boolean hasConflict = false; Set<Long> newCourseIds = new HashSet<>(); for (CourseIntelligentPageResponse course : combination) { if (usedCourseIds.contains(course.getId())) { hasConflict = true; break; } newCourseIds.add(course.getId()); } if (hasConflict) continue; // 选择当前组合 usedCourseIds.addAll(newCourseIds); currentSelection.put(currentGroup, new ArrayList<>(combination)); // 递归下一个组 dfsCrossGroups(groupCombinationsMap, groupKeys, currentIndex + 1, currentSelection, usedCourseIds, results, maxResults); // 回溯 usedCourseIds.removeAll(newCourseIds); currentSelection.remove(currentGroup); if (results.size() >= maxResults) return; } } /** * 获取唯一组合 */ private List<List<CourseIntelligentPageResponse>> getUniqueCombinations( List<List<CourseIntelligentPageResponse>> allCombinations, int maxSize) { Set<String> fingerprints = new HashSet<>(); List<List<CourseIntelligentPageResponse>> result = new ArrayList<>(); for (List<CourseIntelligentPageResponse> combination : allCombinations) { String fingerprint = generateCombinationFingerprint(combination); if (!fingerprints.contains(fingerprint)) { fingerprints.add(fingerprint); result.add(combination); if (result.size() >= maxSize) break; } } return result; } /** * 生成组合指纹 */ private String generateCombinationFingerprint(List<CourseIntelligentPageResponse> combination) { return combination.stream() .map(c -> String.valueOf(c.getId())) .sorted() .collect(Collectors.joining(",")); } /** * 备用方法:快速生成近似组合(当精确组合不足时) */ public List<List<CourseIntelligentPageResponse>> generateApproximateCombinations( int targetHours, int minCourses, int maxCourses, List<CourseIntelligentPageResponse> courses, int numCombinations, int tolerance) { List<CourseIntelligentPageResponse> validCourses = courses.stream() .filter(c -> c.getHourCount() > 0) .sorted((c1, c2) -> Integer.compare(c2.getHourCount(), c1.getHourCount())) .limit(MAX_TOTAL_COURSES) .collect(Collectors.toList()); List<List<CourseIntelligentPageResponse>> results = new ArrayList<>(); Set<String> fingerprints = new HashSet<>(); // 尝试目标学时附近的组合 for (int offset = 0; offset <= tolerance && results.size() < numCombinations; offset++) { for (int hours = targetHours - offset; hours <= targetHours + offset; hours++) { if (hours <= 0) continue; List<List<CourseIntelligentPageResponse>> combinations = findCombinationsBacktrackOptimized(validCourses, hours, minCourses, maxCourses, numCombinations - results.size()); for (List<CourseIntelligentPageResponse> comb : combinations) { String fingerprint = generateCombinationFingerprint(comb); if (!fingerprints.contains(fingerprint)) { fingerprints.add(fingerprint); results.add(comb); if (results.size() >= numCombinations) break; } } if (results.size() >= numCombinations) break; } } return results; } }优化,使用内存小,cup小
最新发布
10-11
在C/C++开发中,`corrupted double-linked list` 错误通常表示堆内存管理结构遭到破坏。这类错误常见于使用 `malloc`、`free`、`new` 或 `delete` 等动态内存管理函数时出现不当操作。 ### 常见原因分析 1. **越界写入(Buffer Overflow)**:当程序向分配的内存块之外的区域进行写操作时,可能覆盖了内存管理器维护的数据结构,例如堆链表中的指针信息。 2. **重复释放(Double Free)**:对同一块内存调用多次 `free` 或 `delete`,可能导致堆链表的前后指针指向无效地址,从而破坏双向链表结构。 3. **释放未分配的内存(Invalid Free)**:尝试释放一个未通过 `malloc` 或 `new` 分配的指针,或已经释放过的内存。 4. **内存泄漏(Memory Leak)**:虽然不会直接导致堆损坏,但长期运行的程序如果存在大量内存泄漏,可能引发后续内存分配失败,间接导致异常行为。 5. **跨库内存分配/释放问题**:例如在一个共享库中使用 `malloc` 分配内存,而在另一个库中使用 `free` 释放,若链接方式不一致(如静态与动态链接混用),也可能破坏堆结构。 ### 调试方法 1. **GDB调试**: - 使用 GDB 捕获崩溃现场,查看堆栈跟踪以定位出错位置。 - 检查涉及内存分配和释放的代码路径是否正确,尤其是 `malloc` 和 `free` 的匹配情况。 2. **Valgrind工具**: - 利用 Valgrind 的 Memcheck 工具检测非法内存访问和内存泄漏问题。 - 示例输出如 `Invalid write of size 8` 表明程序在某个内存块之后进行了非法写入操作,这可能是缓冲区溢出 [^2]。 - Valgrind 可以帮助识别出具体的内存访问违规行为,并指出相关代码行。 3. **AddressSanitizer (ASan)**: - ASan 是一种快速的内存错误检测工具,集成在 GCC 和 Clang 中。 - 它能高效地发现堆栈溢出、全局变量溢出、使用已释放内存等问题。 - 编译时加入 `-fsanitize=address` 并运行程序即可获得详细的诊断信息。 4. **检查内存分配与释放逻辑**: - 确保每次 `malloc` 或 `new` 都有对应的 `free` 或 `delete`。 - 避免对同一个指针调用多次 `free`。 - 对数组使用 `new[]` 和 `delete[]` 进行匹配操作。 ### 解决方案 - **修复越界写入**:仔细检查数组、字符串操作等场景,确保不会超出分配的内存范围。可以使用更安全的函数如 `strncpy` 替代 `strcpy`。 - **避免重复释放**:为每个分配的指针设置一个清晰的所有权模型,确保只释放一次。 - **统一内存管理策略**:在同一模块中完成内存分配与释放,特别是在跨库调用时,确保使用相同的内存分配器。 - **使用智能指针(C++)**:利用 `std::unique_ptr` 和 `std::shared_ptr` 自动管理内存生命周期,减少手动释放的风险。 - **启用编译器警告和静态分析**:使用 `-Wall`、`-Wextra` 等选项捕获潜在问题,结合静态分析工具如 Clang Static Analyzer 提前发现隐患。 ### 示例:使用智能指针避免手动管理内存 ```cpp #include <memory> #include <iostream> int main() { // 使用 unique_ptr 自动管理内存 std::unique_ptr<int[]> data(new int[100]); // 使用数据... for (int i = 0; i < 100; ++i) { data[i] = i; } // 不需要手动 delete,离开作用域自动释放 return 0; } ``` 通过上述方法,可以有效定位并修复 `corrupted double-linked list` 错误的根本原因,提升程序的稳定性和健壮性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值