2015-06-05 63 views
6

我在Java中的foreach循環(這裏的簡化版本)重構的foreach用於循環

List<String> names = getNames(); 
for(String name:names) { 
    doSomething(name); 
} 

有沒有重構這對傳統的for循環自動化的方式?

我知道該怎麼做手工

List<String> names = getNames(); 
for(int i=0; i<names.size(); i++) { 
    String name = names.get(i); 
    doSomething(name); 
} 

正如你所看到的,有一點需要打字的for語句本身以及再次引入變量name併爲其分配值names.get(i)。總的來說,手動編輯對我來說太容易出錯。

爲什麼我要這樣做?我必須修復一個錯誤,修復方法是從索引1開始,而不是從索引0開始,到索引n-1而不是結束(不幸的是我無法立即修復輸入,我需要等待庫更新如果這被認爲是一個錯誤)。

我試過了什麼?我右鍵單擊了for關鍵字並單擊了「Refactor」,但就我從上下文菜單條目中獲得的內容而言,沒有任何內容會爲我完成這項工作。

爲什麼我認爲這在理論上可行?因爲Visual Studio(C#)的Resharper中存在類似的功能。

FYI:我使用Eclipse月神SR 2(4.4.2)

+1

是否有可能引入新的方法,而不是「getNames」返回列表中沒有第一和最後的項目? –

+0

@DevBlanked:當然這在技術上是可能的,但是這並不意味着我手動編寫了一個循環來複制除第一個和最後一個項目以外的所有內容? –

+0

不是真的,您可以刪除提供其索引的第一個和最後一個項目,https://docs.oracle.com/javase/7/docs/api/java/util/List.html#remove(int)。 –

回答

9

鼠標懸停for聲明中,右鍵單擊,快速修復(按Ctrl +),轉換爲索引循環。

應該工作!

+3

「快速修復」,什麼是* * $§名稱!沒有什麼可以修復的。 OMG ... –

+1

然後稱之爲'ctrl + 1'動作...順便說一句,你不需要突出顯示'for'語句,光標除了它就足夠了。 – Holger

+0

@Thomas,確切地說,Eclipse提供了用於糾正問題(錯誤/警告)的「快速修復」,以及用於其他典型修改的「快速輔助」。循環轉換是一種「快速輔助」。只是爲了方便,兩個動作都綁定到'ctrl-1'。 –

0

小心使用這個重構。

原因是對於傳統的鏈表,你的第二個for循環公式是O(N * N),因爲你必須遍歷鏈表以評估names.get(i);。這可能會變得昂貴。

for(String name:names) {移動時請考慮性能影響。修復你的直接錯誤,並保留當前的「大O」可能會有更好的方法。

for(String name : names.subList(1, names.size() - 1)) {

是一種這樣的方式(確認@JB Nizet)。

+0

雖然原則上正確,但沒有任何理智的程序員總是使用LinkedList。 'O(1)'插入成本的優勢只有在這樣大的列表中才能得到回報,以致每元素內存消耗非常高的缺點使其無法使用。 – Holger

6

在我的Eclipse(開普勒RC2)它的工作原理,選擇for關鍵字,或者使用快速修復從上下文菜單或打CTRL + 爲快捷。 Eclipse然後爲我提供了「轉換爲索引」的'循環'或'轉換爲基於迭代器'的'循環'。

Screenshot of quick fix options

+0

謝謝。也適用於Luna 4.4.2。 –

7
List<String> names = getNames(); 
names = names.subList(1, names.size() - 1); 
for(String name : names) { 
    doSomething(name); 
} 

當然,你可以將它放入一個可重複使用的方法,如果你需要做幾次:

public static List<String> fixList(List<String> names) { 
    return names.subList(1, names.size() - 1); 
} 

,然後用它作爲

List<String> names = fixList(getNames()); 
for(String name : names) { 
    doSomething(name); 
} 
+1

好吧,不完全是我要求的,但絕對好,因爲如果我得到庫更新,我只需要刪除一行代碼(執行修復)。 –

+1

這樣可以解決你遇到的問題,如果你在哪裏尋找答案,我會將'fixList'更改爲'trimList',並添加參數'beginIndex'和'endIndex',使得函數更加可重用。 – Ian2thedv

-2

當使用Java 8你可以使用流api

names.stream().skip(1).reverse().skip(1).reverse().foreach(
    name -> do something(name) 
); 

S omething像這樣...

+2

Stream上沒有reverse()方法。 –

+0

除此之外,這不是提問者要求的; 'Stream'沒有'reverse'方法,'forEach'不遵守源順序,因此需要'forEachOrdered'。 – Holger

1

您可以使用:

names = names.subList(1, names.size()-1); 
for (String name : names) { 
    doSomething(name); 
} 

或手動:

for (int i = 1; i < names.size()-1; i++) { 
    String name = names.get(i); 
    doSomething(name); 
} 

但我第一個喜歡使用。

0

不要去索引迭代! 這對於List的所有實現都不能很好地執行。

如果此代碼很熱,那麼去Iterator並讓JIT優化Iterator就好多了。

因此,要麼寫:

List<String> names = getNames(); 
for (String name : names.subList(1, names.size() - 1)) { 
    doSomething(name); 
} 

或者說(一個分配以內):

Iterator<String> it = getNames().iterator(); 
it.next(); // You seem to be sure there is more than one element in the list 
while (it.hasNext()) { 
    String name = it.next(); 
    doSomething(name); 
}