자바 for 와 foreach 에 대해 효율 과 안전 을 동시에 고려 합 니 다.

for 와 foreach 에 대해 효율 과 안전 을 동시에 고려 합 니 다.
배열 에 대한 접근 은 for 방식 을 사용 해 야 합 니 다. 성능 이 더 높 기 때 문 입 니 다.아래 코드 는 적절 하 다.
Object[] objArray = ...;
int objArrayLength = objArray.Length;
for (int i = 0; i < objArrayLength; ++i)
{
    // do something ...
}

String str = ...;
int strLength = str.Length;
for (int i = 0; i < strLength; ++i) 
{
   // do something ...
}

ArrayList 와 같은 아래 표 시 를 사용 하여 무 작위 로 접근 할 수 있 는 데이터 구 조 는 아래 표 시 를 사용 하여 접근 합 니 다. foreach 방식 보다 순서 적 으로 접근 하고 속도 가 빠 릅 니 다.foreach 이렇게 쓰 면 사용 하 는 과정 에서 추가 대상 인 Enumerator 가 생 성 되 고 방문 할 때마다 더 많은 조작 이 필요 하 며 성능 이 떨 어 집 니 다.다음 두 가지 쓰기 로 컴 파일 된 코드 는 같 습 니 다.
第一种写法:
IList list = new ArrayList();
IEnumerator iter = list.GetEnumerator();
try
{
    while (iter.MoveNext())
    {
        Object obj = iter.Current;
        //do something ...
    }
}
finally
{
    IDisposable disposableObj = iter as IDisposable;
    if (disposableObj != null)
    {
        disposableObj.Dispose();
    }
}

第二种写法:
IList list = new ArrayList();
foreach (Object obj in list)
{
    //do something ...
}

이 두 가지 표기 법 에 비해 첫 번 째 표기 법 은 매우 수 다스 러 워 서 C\# foreach 의 문법 을 도입 했다.첫 번 째 쓰기 관찰 을 통 해 foreach 는 GetEnumerator 를 통 해 IEnumerator 대상 을 얻 고 IEnumerator 대상 을 통 해 MoveNext () 방법 을 실행 하고 Current 속성 을 가 져 와 옮 겨 다 닙 니 다.
저 희 는 Reflector 도 구 를 통 해 mscorlib. dll 에서 System. collection. Array List 의 실현 을 확인 합 니 다.
//간단하게 보기 위해 서 저 는 Array List 의 Add, Clear, GetEnumerator 코드 만 보 여 줍 니 다.
public class ArrayList
{
    //这是一个版本标识,ArrayList对象,每做一个修改操作,_version都会加1
    private int _version;

    public virtual int Add(object value)
    {
        int num1;
        if (this._size == this._items.Length)
        {
            this.EnsureCapacity((this._size + 1));
        }
        this._items[this._size] = value;
        ++this._version; //注意此处
        this._size = ((num1 = this._size) + 1);
        return num1;
    }

    public virtual void Clear()
    {
        Array.Clear(this._items, 0, this._size);
        this._size = 0;
        ++this._version; //注意此处
    }

    //每次调用GetEnumerator方法,都会构造一个FastArrayListEnumerator
    //或者ArrayListEnumeratorSimple对象。
    public virtual IEnumerator GetEnumerator()
    {
        if (base.GetType() == typeof(ArrayList))
        {
            return new ArrayList.FastArrayListEnumerator(this);
        }
        return new ArrayList.ArrayListEnumeratorSimple(this);
    }
}

위 코드 를 통 해 알 수 있 듯 이 Array List 는version 구성원 변 수 를 버 전 표지 로 하 는 경우 Add, Clear 등 Array List 내용 을 수정 하 는 작업 을 수행 할 때마다 버 전 번 호 를 1 로 추가 하고 GetEnumerator 방법 을 호출 할 때마다 FastArray ListEnumerator 나 Array ListEnumerator Simple 대상 을 구성 합 니 다.우리 다시 보 자.
FastArrayListEnumerator的实现:
class FastArrayListEnumerator
{
    private int version;

    internal FastArrayListEnumerator(ArrayList list)
    {
        this.list = list;
        this.index = -1;

        //获取构建FastArrayListEnumerator对象时ArrayList的版本号
        this.version = list._version; 

        this.lastIndex = (list._size - 1);
    }

    public bool MoveNext()
    {
        int num1;

        //比较ArrayList当前的版本号,
        //是否和构建FastArrayListEnumerator对象时的版本号一致
        //如果不一致,则抛出异常。
        if (this.version != this.list._version)
        {
            throw new InvalidOperationException(
                Environment.GetResourceString("InvalidOperation_EnumFailedVersion")
                );
        }

        //... ... 
    }
}

FastArray List Enumerator 대상 이 구축 되 었 을 때, 당시 Array List 의 버 전 번 호 였 습 니 다.MoveNext () 작업 을 수행 할 때 Array List 의 현재 버 전 번호 가 FastArray List Enumerator 대상 이 구 축 된 버 전 번호 와 일치 하 는 지 확인 하고 일치 하지 않 으 면 이상 을 던 집 니 다.
Enumerator 에서 버 전 검사 처 리 를 했 기 때문에 foreach 를 사용 하 는 것 은 스 레 드 가 안전 하고 for 를 사용 하 는 것 은 가끔 입 니 다.왜 일 까요?foreach 를 사용 하여 대상 을 옮 겨 다 니 는 과정 에서 다른 스 레 드 가 List 의 내용 을 수정 하면 추가 하거나 삭제 하면 알 수 없 는 오류 가 발생 하고 foreach 를 사용 하면 오류 정 보 를 정확하게 던 질 수 있 습 니 다.
위 에서 말 한 바 와 같이 결론 은 다음 과 같다.
for 를 사용 하여 더욱 효율 적 입 니 다.
foreach 를 사용 하면 더욱 안전 합 니 다.
그럼 어떻게 선택 할 까요?제 제안 은 전역 적 으로 다 중 스 레 드 가 접근 할 수 있 는 데이터 구조 대상 에서 foreach 를 사용 하 는 것 입 니 다.그리고 로 컬 변 수 는 for 를 사용 하여 효율 과 안전 을 병행 합 니 다!예 를 들 면:
public void F1(IList globalList)
{
    IList waitForDeleteList = new ArrayList();

    //全局变量,使用foreach,保证线程
    foreach (Object item in globalList)
    {

        if (condition)
        {
            waitForDeleteList.Add(item);
        }
    }

    //本地变量使用for,保证效率
    int waitForDeleteListCount = waitForDeleteList.Count;
    for (int i = 0; i < waitForDeleteListCount; ++i)
    {
        globalList.Remove(waitForDeleteList[i]);
    }
}

이상 의 건 의 는 자바 환경 에서 도 사용 하 는 것 에 대해 저 는 JDK 1.4 의 자바 util. Array List 의 실현,. NET Framework 의 실현 과 JDK 의 실현 을 읽 은 적 이 있 습 니 다. 거의 똑 같 습 니 다. 표절 여 부 는 인 견 지 를 보 았 습 니 다.위의 C\# 코드 는 자바 환경 에서 다음 과 같 아야 합 니 다.
public void f1(List globalList) {
    List waitForDeleteList = new ArrayList();
    //全局变量,使用Iterator遍历,保证线程
    Iterator iter = globalList.iterator();
    while (iter.hasNext()) {
        Object item = iter.next();
        if (condition) {
            waitForDeleteList.add(item);
        }
    }
    
    //本地变量使用for,保证效率
    int waitForDeleteListCount = waitForDeleteList.size();
    for (int i = 0; i < waitForDeleteListCount; ++i) {
        globalList.remove(waitForDeleteList.get(i));
    }
}

상기 코드 는 이 작업 을 하 는 가장 좋 은 알고리즘 이 아 닙 니 다. 더 높 은 효율 이 필요 하 다 면 다음 과 같이 수정 하 십시오.
C#版本
public void F1(IList globalList)
{
    bool condition = true;
    IList waitForDeleteList = new ArrayList();

    //全局变量,使用foreach,保证线程
    int itemIndex = 0;
    foreach (Object item in globalList)
    {
        if (condition)
        {
            waitForDeleteList.Add(index);
        }
        ++itemIndex;
    }

    //本地变量使用for,保证效率
    int waitForDeleteListCount = waitForDeleteList.Count;
    for (int i = waitForDeleteListCount - 1; i >= 0; --i)
    {
        index = (int) waitForDeleteList[i];
        globalList.RemoveAt(itemIndex);
    }
}
Java版本:
public void f1(List globalList) {
    List waitForDeleteList = new ArrayList();
    //全局变量,使用Iterator遍历,保证线程
    Iterator iter = globalList.iterator();
    int index = 0;
    while (iter.hasNext()) {
        Object item = iter.next();
        if (condition) {
            waitForDeleteList.add(new Integer(index));
        }
        ++index;
    }
    
    //本地变量使用for,保证效率
    int waitForDeleteListCount = waitForDeleteList.size();
    for (int i = waitForDeleteListCount - 1; i >= 0; --i) {
       index = ((Integer) waitForDeleteList.get(i)).intValue();
        globalList.remove(index);
    }
}

좋은 웹페이지 즐겨찾기