《partner4java 讲述 java基础》之第一步:list 、set 、map 粗浅性能对比分析

Map与List及Vector性能比较 Map与List性能比较 1.Collection接口与Map的总体框架图 Collection  ├List  │├LinkedList  │├ArrayList  │└Vector  │ └Stack  └Set  Map  ├Hashtable  ├HashMap  └WeakHashMap   由上图可以看出:List和Set都源自Collection,而Map自成 阅读详情

不知道有多少同学和我一样,工作五年了还没有仔细看过list、set的源码可怜,一直停留在老师教导的:“LinkedList插入性能比ArrayList好,LinkedList顺序遍历性能比ArrayList好”的世界里。可是真是如此么?本文很“肤浅”的对比和分析了几种常用的集合,“高手”可以就此打住不必往下阅读了。。。


本文分开介绍了List、Map、Set:

(测试环境:win7、jdk、4G、i3;文章示例为了节省篇幅,只会列出测试大体形式和遍历次数)

第一部分:List

1.add(E e)

==============================性能测试=================================

(1)表格统计的差异在于new的方式不同:

		for (int i = 0; i < 10000; i++) {
			List<Integer> list = new LinkedList<Integer>();
			for (int j = 0; j < 10000; j++) {
				list.add(j);
			}
			list = null;
		}

new方式消耗时间(毫秒)
new LinkedList<Integer>()3420
new ArrayList<Integer>()3048
new ArrayList<Integer>(10000)2280
new Vector<Integer>() 4045
new Vector<Integer>(10000)3859

(2)我们变化一下集合的长度和遍历次数:

		for (int i = 0; i < 1000000; i++) {
			List<Integer> list = new LinkedList<Integer>();
			for (int j = 0; j < 100; j++) {
				list.add(j);
			}
			list = null;
		}
new方式消耗时间(毫秒)
new LinkedList<Integer>()2286
new ArrayList<Integer>()2832
new ArrayList<Integer>(10000)1714
new Vector<Integer>() 3937
new Vector<Integer>(10000)3184


*************************************************源码分析*************************************************

似乎并没有看到期待的差异,若非“冒充下大牛”纠结一下区别:

1、若集合长度比较小(小于百位),LinkedList比ArrayList的插入性能稍胜一筹。

2、但是当长度达到五位数时,ArrayList的插入性能反而会比LinkedList好一些。

3、若你能预知ArrayList的长度,可以完胜LinkedList。(原因后面会说)

4、Vector的作用不在一个纬度上,不过也没有想象中的那么差。


LinkedList.add:

    先调用了自身的add:
    public boolean add(E e) {
	addBefore(e, header);
        return true;
    }
    然后又调用了addBefore,表示插入在谁之前(有点绕,因为是双项链):
    private Entry<E> addBefore(E e, Entry<E> entry) {
	Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
	newEntry.previous.next = newEntry;
	newEntry.next.previous = newEntry;
	size++;
	modCount++;
	return newEntry;
    }
    用于维护指定前后关系:
    private static class Entry<E> {
	E element;
	Entry<E> next;
	Entry<E> previous;

	Entry(E element, Entry<E> next, Entry<E> previous) {
	    this.element = element;
	    this.next = next;
	    this.previous = previous;
	}
    }
也就是说LinkedList的上下级维护关系是借助了指针,若任意位置插入,则是先查找到before前的entry,然后重指原有位置前后元素的指针。


ArrayList.add:

首先判断下是否超过了最大长度数组长度,若超过会重新扩展拷贝(这也就说明了,为什么当我们在newArrayList时指定合适的长度会提升性能)

    相比LinkedList来说就简单了狠多:
    public boolean add(E e) {
	ensureCapacity(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
    }
    //首先判断下是否超过了最大长度数组长度,若超过会重新扩展拷贝(这也就说明了,为什么当我们在newArrayList时指定合适的长度会提升性能)
    public void ensureCapacity(int minCapacity) {
	modCount++;
	int oldCapacity = elementData.length;
	if (minCapacity > oldCapacity) {
	    Object oldData[] = elementData;
	    int newCapacity = (oldCapacity * 3)/2 + 1;
    	    if (newCapacity < minCapacity)
		newCapacity = minCapacity;
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
	}
    }
    //默认长度10
    public ArrayList() {
	this(10);
    }

通过上面的源码可以理解出为什么当集合的长度会左右LinkedList和ArrayList的插入性能PK。影响ArrayList性能损耗的一大元凶就是数组的不断增长拷贝,LinkedList由于自身的特性当数据插入时需要借助特殊的内部类“Entry”来维护插入数据的上下级链。


2.add(int index, E element)

通过上面的分析出现了一个想法,如果是

随机插入位置呢?

==============================性能测试=================================

(1)

for (int i = 0; i < 100; i++) {
	List<Integer> list = new LinkedList<Integer>();
	for (int j = 0; j < 10000; j++) {
		list.add(list.size() / 2, j);
	}
	list = null;
}
new方式消耗时间
new LinkedList<Integer>()15782
new ArrayList<Integer>()3513
new ArrayList<Integer>(10000)3490

(2)我们变化一下集合的长度和遍历次数:

		for (int i = 0; i < 100000; i++) {
			List<Integer> list = new LinkedList<Integer>();
			for (int j = 0; j < 100; j++) {
				list.add(list.size() / 2, j);
			}
			list = null;
		}
new方式消耗时间
new LinkedList<Integer>()880
new ArrayList<Integer>()1262
new ArrayList<Integer>(10000)2308

*************************************************源码分析*************************************************

从纯插入性能上来说,随机插入LikedList要比ArrayList性能好:(至于为什么当LinkedList集合长度为10000时性能变化会如此之大,我们后面的get会有介绍)

LikedList.add(int index, E element) :

大体分为两个步骤

    public void add(int index, E element) {
        addBefore(element, (index==size ? header : entry(index)));
    } 
    //第一步获取到addBefore需要的插入位置(entry),第二步如上
    private Entry<E> entry(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Entry<E> e = header;
        if (index < (size >> 1)) {
            for (int i = 0; i <= index; i++)
                e = e.next;
        } else {
            for (int i = size; i > index; i--)
                e = e.previous;
        }
        return e;
    }
所以从代码上看, LikedList. add(int index, E element) 没有理由在集合长度为10000时会有这么大的差异,除非entry(int index)存在问题(我们后面可能要说的hash也正是为了避免遍历)。


ArrayList.add(int index, E element) :

大体分为三步

第二步暴漏了为什么现在初始指定了集合长度反而不一定是好事。

    public void add(int index, E element) {
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(
		"Index: "+index+", Size: "+size);
	//第一步:扩充长度
	ensureCapacity(size+1);  // Increments modCount!!
	//第二步:挪动数据(这一步决定了为什么现在初始指定了集合长度反而不一定是好事)
	System.arraycopy(elementData, index, elementData, index + 1,
			 size - index);
	//第三步:插入
	elementData[index] = element;
	size++;
    }

3.get(int index)

==============================性能测试=================================

		List<Integer> list = new LinkedList<Integer>();
		for (int j = 0; j < 10000; j++) {
			list.add(j);
		}

		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < 10000; j++) {
				list.get(j);
			}
		}
new方式消耗时间
new LinkedList<Integer>()8349
new ArrayList<Integer>(10000)15
*************************************************源码分析*************************************************

通过这个表首先能够知道如果直接或间接(如模板语言)调用for循环遍历,LikedList的性能要差很多。

LinkedList.get(int index):

    public E get(int index) {
        return entry(index).element;
    }
    //性能损耗在这里,每次都需要线性搜索(遍历链定位位置)
    private Entry<E> entry(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException("Index: "+index+
                                                ", Size: "+size);
        Entry<E> e = header;
        if (index < (size >> 1)) {
            for (int i = 0; i <= index; i++)
                e = e.next;
        } else {
            for (int i = size; i > index; i--)
                e = e.previous;
        }
        return e;
    }

ArrayList.get(int index):

    public E get(int index) {
	//检查是否越界
	RangeCheck(index);
	//直接从数组中取出对应index的数据
	return (E) elementData[index];
    }


4.迭代器

==============================性能测试=================================

		List<Integer> list = new LinkedList<Integer>();
		for (int j = 0; j < 100; j++) {
			list.add(j);
		}

		for (int i = 0; i < 1000000; i++) {
			Iterator<Integer> it = list.iterator();
			while (it.hasNext()) {
				it.next();
			}
			it = null;
		}
new方式消耗时间
new LinkedList<Integer>()1335
new ArrayList<Integer>();3940


*************************************************源码分析*************************************************

LinkedList.iterator():

    private class ListItr implements ListIterator<E> {
	//header为LikedList的成员变量Entry
	private Entry<E> lastReturned = header;
	private Entry<E> next;
	private int nextIndex;
	private int expectedModCount = modCount;

	//这里我们会默认传入0,
	ListItr(int index) {
	    if (index < 0 || index > size)
		throw new IndexOutOfBoundsException("Index: "+index+
							    ", Size: "+size);

 	    //下面的if和else很有意思,为了实现“所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。”
	    //size为外部LikedList的成员变量
	    if (index < (size >> 1)) {
		next = header.next;
		for (nextIndex=0; nextIndex<index; nextIndex++)
		    next = next.next;
	    } else {
		next = header;
		for (nextIndex=size; nextIndex>index; nextIndex--)
		    next = next.previous;
	    }
	}

	//判断是否已经超过长度
	public boolean hasNext() {
	    return nextIndex != size;
	}

	//便宜至下一个元素并返回element
	public E next() {
	    checkForComodification();
	    if (nextIndex == size)
		throw new NoSuchElementException();

	    lastReturned = next;
	    next = next.next;
	    nextIndex++;
	    return lastReturned.element;
	}

	...

	final void checkForComodification() {
	    if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	}
    }
也就是说我们的LinkedList的Iterator性能损耗主要在变换指针,所以对比for遍历方式来说性能提升了很多。


ArrayList.iterator():

    public Iterator<E> iterator() {
	return new Itr();
    }

    private class Itr implements Iterator<E> {
	/**
	 * Index of element to be returned by subsequent call to next.
	 */
	int cursor = 0;

	/**
	 * Index of element returned by most recent call to next or
	 * previous.  Reset to -1 if this element is deleted by a call
	 * to remove.
	 */
	int lastRet = -1;

	/**
	 * The modCount value that the iterator believes that the backing
	 * List should have.  If this expectation is violated, the iterator
	 * has detected concurrent modification.
	 */
	int expectedModCount = modCount;

	public boolean hasNext() {
            return cursor != size();
	}

	public E next() {
            checkForComodification();
	    try {
		//主要内容在这里,又绕回了ArrayList的获取方式
		E next = get(cursor);
		lastRet = cursor++;
		return next;
	    } catch (IndexOutOfBoundsException e) {
		checkForComodification();
		throw new NoSuchElementException();
	    }
	}

    }
ArrayList“很懒”的没有做什么,主要借助了父类AbstractList,获取方式采用了模板方法设计模式(Template Method Pattern)。

总结:无论你遍历ArrayList还是LinkedList都可以尽量采用迭代器。


通过add和get的分析,我们最常用的场景就是单页数据获取,然后利用jstl或velocity等遍历展示:

1、如果能确定遍历采用的for循环建议使用ArrayList并采用带参的构造器指定集合长度(也就是每页的个数);

2、若遍历采用迭代器建议采用LinkedList,因为我们还会有时对dao获取的数据采用缓存策略。

(jstl用的迭代器,可看源码org.apache.taglibs.standard.tag.common.core.ForEachSupport.toForEachIterator方法)


第二部分:Map


1.put(K key, V value)

==============================性能测试=================================

表格统计的差异在于new的方式不同:

		for (int i = 0; i < 100000; i++) {
			Map<Integer, String> map = new TreeMap<Integer, String>();
			for (int j = 0; j < 100; j++) {
				map.put(j, "s" + j);
			}
			map = null;
		}
new方式运行时间
new TreeMap<Integer, String>()2945
new HashMap<Integer, String>()2029
new HashMap<Integer, String>(100)1845
*************************************************源码分析*************************************************

TreeMap.put(K key, V value):

首先确认一点TreeMap采用的“红黑树”二叉查找方式。(具体算法请自行google)

该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。此实现为 containsKey、get、put 和 remove 操作提供受保证的 log(n) 时间开销。

插入大体分为四步:

1、判断是否为初次;

2、获取指定Comparator,若没有指定获取key的父类的实现方式。

3、利用Comparator确定数据存放位置;

4、树的旋转。

    public V put(K key, V value) {
        Entry<K,V> t = root;
	//判断是否存在根节点,或者集合是否存在了数据
        if (t == null) {
            root = new Entry<K,V>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
	//这点是获取构造器传入的Comparator
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
	//若没有指定Comparator,查找父类实现
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
	    //遍历放入确切位置
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<K,V>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
	//树的旋转
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

HashMap.put(K key, V value):

1、HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量 是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数;

2、key的hashcode至关重要。

    //构造一个带指定初始容量和加载因子的空 HashMap
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        // Find a power of 2 >= initialCapacity
        int capacity = 1;
	//取大于等于初始容量最近的2的倍数
        while (capacity < initialCapacity)
            capacity <<= 1;

        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
        table = new Entry[capacity];
        init();
    }
    public V put(K key, V value) {
        if (key == null)
            return putForNullKey(value);
	//计算key的hash值
        int hash = hash(key.hashCode());
	//计算出在第几个“水桶”,计算方式是&与了table.length-1,这应该也是水桶数据是2的倍数的原因
        int i = indexFor(hash, table.length);
	//通过这步可以理解为什么看到好多文档要求key的hashCode“均匀分布”便于均匀落入各个水桶
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

2.get

==============================性能测试=================================

(1)表格统计的差异在于new的方式不同:

		Map<Integer, String> map = new TreeMap<Integer, String>();
		for (int j = 0; j < 100; j++) {
			map.put(j, "s" + j);
		}

		for (int i = 0; i < 100000; i++) {
			for (int j = 0; j < 100; j++) {
				map.get(j);
			}
		}
new方式运行时间
new TreeMap<Integer, String>()542
new HashMap<Integer, String>(100)280

(2)变化下集合的大小(有时我们使用Map存放上万条乃至几十万条数据用于小数据本地快速缓存):

		Map<Integer, String> map = new HashMap<Integer, String>(300000);
		for (int j = 0; j < 300000; j++) {
			map.put(j, "sasd");
		}
		beginTime = System.currentTimeMillis();
		for (int i = 0; i < 100; i++) {
			for (int j = 0; j < 300000; j++) {
				map.get(j);
			}
		}
new方式运行时间
new TreeMap<Integer, String>()5100
new HashMap<Integer, String>(300000)1400

(3)当hashcode为极端情况下:

Map<HashKeyTest, String> map = new TreeMap<HashKeyTest, String>();
for (int j = 0; j < 10000; j++) {
	map.put(new HashKeyTest(j), "sasd");
}
beginTime = System.currentTimeMillis();
for (int i = 0; i < 10; i++) {
	for (int j = 0; j < 10000; j++) {
		map.get(new HashKeyTest(j));
	}
}

public class HashKeyTest implements Comparable<HashKeyTest> {

	private int value;
	...
	
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		HashKeyTest other = (HashKeyTest) obj;
		if (value != other.value)
			return false;
		return true;
	}
	//模拟hashCode的极端情况,返回相同的值
	@Override
	public int hashCode() {
		return 345345435;
	}
	//用于TreeMap的二叉树对比排序
	@Override
	public int compareTo(HashKeyTest o) {
		int thisVal = this.value;
		int anotherVal = o.getValue();
		return (thisVal < anotherVal ? -1 : (thisVal == anotherVal ? 0 : 1));
	}

}
new方式消耗时间
new TreeMap<HashKeyTest, String>()18
new HashMap<HashKeyTest, String>()3480

*************************************************源码分析*************************************************

TreeMap.get(Object key):

基于红黑树查找

    public V get(Object key) {
        Entry<K,V> p = getEntry(key);
        return (p==null ? null : p.value);
    }
    final Entry<K,V> getEntry(Object key) {
        // Offload comparator-based version for sake of performance
        if (comparator != null)
            return getEntryUsingComparator(key);
        if (key == null)
            throw new NullPointerException();
	Comparable<? super K> k = (Comparable<? super K>) key;
        Entry<K,V> p = root;
        while (p != null) {
            int cmp = k.compareTo(p.key);
            if (cmp < 0)
                p = p.left;
            else if (cmp > 0)
                p = p.right;
            else
                return p;
        }
        return null;
    }

HashMap.get(Object key):

代码中很简明的可以看出,如果hashCode不均为出现的问题

    public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
	//若hashCode相同,会导致查找方式就是这里的不停的遍历
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;
        }
        return null;
    }

总结:

1、key如果是自定义对象,一定要有效地重载hashCode(),可参考《覆盖equals时总要覆盖hashCode》;

2、尽量保证hashCode“均为分布”,以便于均匀填充“水桶”;

3、当我们确定Map存放的数据比较多且hashCode分配严重不均匀,切记不要使用HashMap,建议使用TreeMap;

4、正常情况下,也就是我们常把表id作为key时,建议使用HashMap。


Set留给同学自己学习吧。(HashSet其实就是使用的HashMap作为容器)

Fiori Element开发实战:从注解配置到扩展点应用全解析 在企业级应用开发中,声明式框架通过预定义模板和配置驱动的方式,显著提升开发效率并确保UI一致性。其核心原理在于将界面行为抽象为元数据描述,由框架自动生成符合设计规范的应用程序,从而降低前端技术门槛。这一技术价值体现在快速构建标准化业务应用,如列表报表和对象详情页,广泛应用于ERP、CRM等企业管理场景。本文聚焦SAP Fiori Element,深入探讨如何通过OData注解定义数据模型与UI行为,并利用扩展点实现自定义功能,为开发者提供从环境搭建到部署上线的完整实践指南。 阅读详情

相关推荐

多维聚合中的数据变形术:从GROUP BY到动态维度编排

多维聚合是OLAP分析的核心能力,指在三个及以上业务维度(如省份、产品线、时间)上进行协同分组与指标计算的技术过程。其原理超越传统SQL的GROUP BY,需融合分层聚合、窗口上下文感知与维度关系建模,以解决交叉分析中的数值守恒、语义一致性与动态组合难题。技术价值在于支撑实时BI看板、智能预警与自助式分析,显著提升决策响应速度与数据可信度。典型应用场景包括电商销售归因、物流时效分析、金融客户分群等需要高维切片与下钻能力的领域。本文聚焦‘多维聚合’与‘数据变形’两大关键概念,系统拆解抗干扰、可追溯、支持动态维

weixin_33785108的博客 371

Java中 List、Set、Map遍历方式以及性能比较

目录一、简介二、遍历方式1、ArrayList遍历方式(1)for循环遍历(2)foreach循环遍历(3)Iterator迭代器遍历2、LinkedList遍历方式(1)for循环遍历(2)foreach循环遍历(3)Iterator迭代器遍历3、HashSet遍历方式(1)foreach循环遍历(2)Iterator迭代器遍历4、HashMap遍历方式(1)entrySet遍历(2)Iterator迭代器遍历5、LinkedHashMap遍历方式(1)entrySet遍历(2)Iterator迭代器遍历

Davis 9582

Spring Boot项目CORS安全漏洞修复:手写Tomcat过滤器实现精细化跨域控制

跨域资源共享(CORS)是现代Web应用开发中处理跨域请求的核心安全机制。其原理是通过HTTP响应头,由服务器明确告知浏览器哪些外部源被允许访问资源,从而在便利跨域通信的同时,防止恶意网站窃取数据。正确的CORS配置对于保护用户敏感信息、防范CSRF等攻击具有重要技术价值,广泛应用于前后端分离架构、微服务API调用等场景。本文聚焦于CORS配置不当引发的典型安全漏洞,如Origin校验缺失、Credentials与通配符冲突等,并针对Spring Boot + Tomcat技术栈,提供了一套通过自定义过滤器

diandingyin9417的博客 434

数据结构之Map和Set总结

一、概念与模型 1.概念:Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。以前常见的搜索方式有: ①直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢 ②二分查找,时间复杂度为O(logN),但搜索前必须要求序列是有序的 。上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了,而现实中的查找比如: ①根据姓名查询考试成绩 ②通讯录,即根据姓名查询联系方式 ③不重复集合,即需要先搜索关键字是否已经在集合中,可能在查找时进行一些插入和删除的

Poem_coder的博客 3212

GodotSteam插件全解析:轻松集成Steamworks SDK到Godot游戏

游戏引擎与平台SDK的集成是游戏开发中的关键技术环节,它决定了游戏能否充分利用平台提供的社交、分发和变现能力。其核心原理在于通过中间层或插件,将平台的原生API(通常是C++库)封装成引擎脚本能够直接调用的接口,从而打通数据与功能通道。这项技术的价值在于极大降低了开发门槛,让独立开发者和小团队也能高效地为游戏注入成熟的平台服务,如成就系统、云存档和多人联机。在Godot引擎生态中,针对Steam平台的集成需求,GodotSteam插件通过GDExtension架构,将复杂的Steamworks SDK完整封

weixin_30460489的博客 315

AI编排实战:MuleSoft与LangChain协同实现企业级安全AI工作流

AI编排(AI Orchestration)是企业在多系统、多模型环境下实现可控AI落地的核心工程范式,其本质是将数据集成、权限治理、模型调用与合规审计解耦并协同——既非单纯调用大模型API,也非传统ESB式数据搬运。它依托企业级集成平台(如MuleSoft)保障认证、脱敏、审计等刚性能力,交由AI原生框架(如LangChain)专注推理链构建、RAG增强与结构化输出,通过明确定义的接口契约实现能力互补。该模式显著提升AI服务在CRM/ERP等关键业务场景中的可用性、安全性与可审计性,尤其适用于需满足GDP

蓝色妖姬 387

java map和list全遍历读写性能比较

System.out.println("list时间差:" + (ll_list - l_list));System.out.println("map时间差:" + (ll - l));####list读写性能比map读写性能高5到10倍。

mai_li的博客 519

从大数据到精准匹配:技术选型与轻量级社交连接系统实战

在数据处理领域,大数据技术栈如Spark、Hadoop常被用于处理海量、规整的确定性数据,其核心原理在于分布式计算与存储,以解决高吞吐量和高并发的技术挑战。然而,当面对非结构化、小数据量且涉及主观判断的场景时,直接套用大数据框架可能引入不必要的复杂性。从技术价值看,合理的技术选型旨在平衡性能、开发效率与系统可维护性,尤其在涉及用户隐私和实时交互的应用中,轻量级、精准的技术方案往往更具优势。典型的应用场景包括社交匹配、个性化推荐等需要处理多维、主观性数据的系统。本文以构建一个轻量级社交连接系统为例,探讨如何运

weixin_33795806的博客 431

JAVA应用中集成SF的chatter功能及开发步骤

项目中,需要与SF合作,使用SF提供的Chatter功能,即将车的实时数据信息,工况,DTC等数据自动提交到SF的chatter上面,一边让群组内的所有人员共享或帮忙解决问题。所以应用获取到相关数据后,会自动将数据chatter到SF系统上。 [img]http://dl.iteye.com/upload/attachment/574040/5ffdeb18-fc79-3f6d-9233-1...

Kevin 426

MuleSoft+LangChain混合AI编排:企业级智能助手落地实践

AI编排(AI Orchestration)是连接大模型与企业核心系统的关键技术,其本质是构建可审计、可回滚、可复用的AI流水线调度系统。它不替代模型训练,而是解决数据搬运、流程协同与安全治理等生产级问题。在销售智能助手等真实场景中,需融合MuleSoft的企业集成能力(如OAuth2.0治理、字段级脱敏、分布式事务)与LangChain的AI逻辑编排(如RAG检索、结构化推理、Prompt工程),形成‘确定性任务由MuleSoft承载,不确定性任务由LangChain处理’的分层架构。该模式已成功应用于金

weixin_30629653的博客 354

PARL框架破解多智能体串行坍塌:实现真并行调度

多智能体系统中的‘串行坍塌’本质是任务依赖、资源争抢与结果收敛三重约束导致的并行失效,而非单纯并发能力缺失。其核心原理在于传统Agent调度缺乏动态依赖识别、实时资源感知与契约化执行保障,致使理论并行度无法转化为实际吞吐提升。PARL框架通过引入依赖探针、资源感知型负载均衡器和执行契约(Execution Contract)三大机制,在不修改大模型底层的前提下重构调度逻辑,显著释放硬件并行潜力。该技术已验证在生物医药情报分析等典型场景中达成4.5倍端到端加速,适用于需高频调用外部工具、强数据一致性要求及复杂

weixin_34033624的博客 287

大白话说Java设计模式-14-适配器模式(业务实战篇)

本文结合多支付渠道对接、第三方API适配等业务场景详解适配器模式的核心实现与实战应用,讲解类适配器、对象适配器、接口适配器三种实现方式的原理与适用场景,对比适配器模式与桥接模式、装饰器模式的设计差异,分析适配器模式在系统兼容、多源数据统一接入、老系统改造等场景的设计价值,帮助开发者掌握如何在业务中运用适配器模式实现新旧系统平滑对接,降低代码耦合度。

Java后端 | AI智能体应用实战派 | 电脑技能行家 289

柚子租车小程序源码1.4.2深度解析:分销+天地图+蓝牙开锁实战

微信小程序作为轻量级本地化服务载体,其核心能力在于精准定位、实时交互与社交裂变。天地图替代高德实现低成本合规地理服务,蓝牙开锁需兼顾安卓14与iOS系统差异,而分销机制本质是基于用户关系链的实时佣金归因与多级结算。这些技术组合并非孤立功能,而是围绕‘区域租车业务低门槛数字化’这一命题构建的闭环:从地图选车到订单完成,再到邀请转化与财务对账,全程依赖状态一致性保障与微信原生API深度调用。本文以柚子租车小程序源码1.4.2为样本,详解其微服务架构、四层分销嵌入设计及真实部署避坑经验。

327

Coze工作流本质是状态机:三重契约与生产级编排指南

工作流是AI应用开发中连接意图识别、状态管理、多模态响应与外部系统的关键范式。它并非简单流程图,而是融合有限状态机(FSM)与数据流图的混合架构,强调状态确定性、数据不可变性与Schema优先原则。在低代码AI平台如Coze中,工作流真正价值在于支撑真实业务闭环——如跨境电商订单状态机、简历结构化筛选、合同条款联动审批等场景。理解其底层‘对话契约、数据契约、协议契约’三重关系,才能规避变量滥用、上下文丢失、API字段错配等高频故障。本文以Coze 2026版为实践蓝本,深入解析状态持久化、跨Bot桥接、HT

weixin_34050005的博客 363

《partner4java 讲述 java基础》之第一步:list 、set 、map 粗浅性能对比分析 - java相关技术(partner4java专栏)

《partner4java 讲述 java基础》之第一步:list 、set 、map 粗浅性能对比分析 - java相关技术(partner4java专栏)

用Codex自动化挖掘电梯行业外贸客户:从关键词到22维深度分析

在B2B外贸客户开发中,精准定位垂直行业潜在客户是核心挑战。传统手动搜索效率低下,而数据驱动的工作流正成为解决方案。其原理在于将模糊的业务需求转化为机器可识别的结构化查询,通过组合行业核心关键词(如“Elevator Manufacturer”、“Elevator Maintenance”)与商业角色描述,系统性地从海量数据中筛选目标。这种自动化抓取技术的价值在于,它不仅生成客户名单,更通过多维数据分析(如公司规模、业务标签、数字足迹)构建初步的客户画像,为后续的优先级排序和个性化触达提供情报基础。在工业制

weixin_34054866的博客 455

构建企业级密钥扫描代理:从非结构化文档中智能提取敏感信息

在信息安全领域,密钥管理是保障系统安全的核心环节。其基本原理在于对敏感凭证(如API密钥、数据库密码)进行集中化、加密化的生命周期管理,以防止泄露带来的数据与资产风险。传统上,密钥应存储在专用的密钥管理系统中,但现实中它们常因开发运维流程的疏漏,散落在各类非结构化文档内,如Wiki页面、配置文件甚至聊天记录,形成巨大的安全盲区。为解决此问题,现代安全工程实践引入了自动化扫描技术,通过结合规则引擎与机器学习模型,不仅能识别固定模式的密钥,还能理解其上下文语义,从而精准评估风险。这种技术广泛应用于企业安全左移、

weixin_34294649的博客 441

导出库的版本_Windows下PaddleOCR在C++中的推理部署(CPU版本)CMake + VS2017

PaddleOCR是一个与OCR相关的开源项目,不仅支持超轻量级中文OCR预测模型,总模型仅8.6M(单模型支持中英文数字组合识别、竖排文本识别、长文本识别,其中检测模型DB(4.1M)+识别模型CRNN(4.5M)),而且提供多种文本检测训练算法(EAST、DB)和多种文本识别训练算法(Rosetta、CRNN、STAR-Net、RARE)。本文将教大家通过PaddleOCR(CPU版...

weixin_31304817的博客 1917
上一篇: Could not create the view: An unexpected exception was thrown. 电脑突然断电,myeclipse非正常关闭,出现错误
下一篇: 计算程序所需线程总数 -- 摘自《Java虚拟机并发编程》
partner4java
博客等级 码龄17年 481粉丝 183原创
评论 14
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值