Is there a way to access an iteration-counter in Java's for-each loop?
Java的每个循环都有一种方法吗?
1 2 3 |
了解循环处理的频率?
除了使用旧的和众所周知的
1 2 3 4 5 |
在for each循环中有这样一个计数器的唯一方法是什么?
没有,但是你可以提供你自己的柜台。
这样做的原因是for each循环内部没有计数器;它基于iterable接口,即它使用
还有另一种方法。
假设您编写自己的
1 2 3 4 5 | for (Index<String> each: With.index(stringArray)) { each.value; each.index; ... } |
其中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class With { public static <T> Iterable<Index<T>> index(final T[] array) { return new Iterable<Index<T>>() { public Iterator<Index<T>> iterator() { return new Iterator<Index<T>>() { index = 0; public boolean hasNext() { return index < array.size } public Index<T> next() { return new Index(array[index], index++); } ... } } } } } |
最简单的解决方案是运行自己的计数器,因此:
1 2 3 4 5 |
这是因为没有实际的保证集合中的项(
例如,请参见以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | import java.util.*; public class TestApp { public static void AddAndDump(AbstractSet<String> set, String str) { System.out.println("Adding [" + str +"]"); set.add(str); int i = 0; for(String s : set) { System.out.println(" " + i +":" + s); i++; } } public static void main(String[] args) { AbstractSet<String> coll = new HashSet<String>(); AddAndDump(coll,"Hello"); AddAndDump(coll,"My"); AddAndDump(coll,"Name"); AddAndDump(coll,"Is"); AddAndDump(coll,"Pax"); } } |
当你运行它的时候,你可以看到如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
也就是说,顺序不被认为是集合的显著特征。
没有手动计数器也有其他的方法,但这是一个值得怀疑的好处。
在Java 8中使用LAMBDAS和功能接口使得创建新的环路抽象成为可能。我可以循环使用索引和集合大小的集合:
1 2 |
输出:
1 2 3 4 | 1/4: one 2/4: two 3/4: three 4/4: four |
我执行为:
1 2 3 4 5 6 7 8 9 10 11 | @FunctionalInterface public interface LoopWithIndexAndSizeConsumer<T> { void accept(T t, int i, int n); } public static <T> void forEach(Collection<T> collection, LoopWithIndexAndSizeConsumer<T> consumer) { int index = 0; for (T object : collection){ consumer.accept(object, index++, collection.size()); } } |
可能性是无限的。例如,我创建了一个抽象,它只对第一个元素使用一个特殊的函数:
1 2 3 |
正确打印逗号分隔列表:
1 | one,two,three,four |
我实施如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | public static <T> void forEachHeadTail(Collection<T> collection, Consumer<T> headFunc, Consumer<T> tailFunc) { int index = 0; for (T object : collection){ if (index++ == 0){ headFunc.accept(object); } else{ tailFunc.accept(object); } } } |
图书馆将开始弹出去做这些事情,或者你可以自己滚动。
恐怕用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
注意,列表界面提供了访问
(编辑)
对于您更改的示例:
1 2 3 4 5 | for(ListIterator<String> it =l.listIterator(); it.hasNext() ;) { int i = it.nextIndex(); doSomethingWith(it.next(), i); } |
Java 8引入了EDCOX1×11 E/OCXX1×12的方法,对于每个EDCOX1,13,EDCX1,14个实现,与每个循环的"经典"相比,效率更高。但是,在这种情况下,也没有提供索引。这里的技巧是在lambda表达式之外使用
1 2 3 4 5 | final AtomicInteger indexHolder = new AtomicInteger(); map.forEach((k, v) -> { final int index = indexHolder.getAndIncrement(); // use the index }); |
1 2 3 4 5 |
这是句法上的甜头,但显然有很多人对这个特性提出了要求。但是,在获得批准之前,您必须自己计算迭代次数,或者使用带有
惯用解决方案:
1 2 3 4 5 6 7 |
this is actually the solution that Google suggests in the Guava discussion on why they did not provide a
CountingIterator .
尽管SOO还有很多其他的方式来实现这一点,但我会为一些不满意的用户分享我的方式。我正在使用Java 8的ItSt流特性。
1。数组
1 2 3 4 5 |
2。表
1 2 3 4 5 6 7 | List<String> strings = new ArrayList<String>(); Collections.addAll(strings,"A","B","C","D"); IntStream.range(0, strings.size()).forEach(index-> { System.out.println("index:" + index); System.out.println("value:" + strings.get(index)); }); |
如果你需要在for-each循环中有一个计数器,你必须计算你自己。据我所知,没有内置计数器。
帕克斯的回答有一个"变种"…-)
1 2 3 4 |
1 2 3 4 5 |
方法有很多种,但方法是一种方法。
我发现使用带有递增索引的简单for循环是最有效、最可靠的解决方案,如本文所述:https://stackoverflow.com/a/3431543/2430549
对于偶尔只需要索引的情况,例如在catch子句中,有时会使用indexof。
1 2 3 4 5 6 7 8 |
下面是一个我如何做到这一点的例子。这将在for each循环中获取索引。希望这有帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class CheckForEachLoop { public static void main(String[] args) { int[] myIntArray = new int[11]; String[] months = new String[] {"JANUARY","FEBRUARY","MARCH","APRIL","MAY","JUNE","JULY","AUGUST", "SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER" }; for (String s : months) { if (s == months[2]) { // location where you can change } } System.out.println(s); } } |
我有点惊讶没有人提出以下建议(我承认这是一种懒惰的方法…);如果StringArray是某种类型的列表,则可以使用StringArray.IndexOf之类的函数返回当前计数的值。
注意:这假定列表中的元素是唯一的,或者它们是否是非唯一的并不重要(因为在这种情况下,它将返回找到的第一个副本的索引)。
在某些情况下,这就足够了…