简体   繁体   English

Java为什么不存在用于(每个)循环的第三种语法?

[英]Java why does no third syntax for for (each) loops exist?

I know that currently there are two approaches to loop over an List . 我知道,目前有两种方法可以遍历List But let's complicate it a bit more, consider: 但让我们复杂一点,请考虑:

  • You iterate over List<E> list . 您遍历List<E> list
  • You want to keep track of an int y on every iteration. 您希望在每次迭代中都跟踪一个int y
  • There exists a function process(E elem, int y) that processes an item. 存在一个process(E elem, int y)的功能process(E elem, int y)

Option 1: 选项1:

for (int i = 0, y = 0; i < list.size(); i++, y++) {
    process(list.get(i), y);
}

which actually just is 其实就是

for (int i = 0; i < list.size(); i++) {
    process(list.get(i), i);
}

Option 2: 选项2:

int y = 0;
for (E elem : list) {
    process(elem, y);
    y++;
}

which can be rewritten to 可以重写为

int y = 0;
for (E elem : list) {
    process(elem, y++);
}

However why does the following not exist? 但是为什么不存在以下内容? What are the objections to it not existing? 对它不存在哪些异议?

Option 3: 选项3:

for (int y = 0; E elem : list; y++) {
    process(elem, y);
}

Two arguments to have this construct: 具有此构造的两个参数:

  • Both foreach syntaxes are distinguishable 两种foreach语法都是可区分的
  • Many objects implement Iterable<E> , but have no for counterpart. 许多对象实现Iterable<E> ,但没有for对应对象。 This happens when an Iterable<E> has no order associated with it for example. 例如,当Iterable<E>没有与之关联的顺序时,就会发生这种情况。

This is close to the proposed variant 3: 这接近于建议的变体3:

int y = 0;
for (Iterator<E> it=list.iterator(); it.hasNext(); y++) {
   process(it.next(), y);
}

or 要么

Iterator<E> it=list.iterator();
for (int y = 0; it.hasNext(); y++) {
   process(it.next(), y);
}

or 要么

Iterator it;int y;
for (y = 0, it=list.iterator(); it.hasNext(); y++) {
    process(it.next(), y);
}

Because it's excessive? 因为过量吗? In this case y doesn't bear any sense and code can be easily rewritten as you've shown. 在这种情况下, y毫无意义,并且您可以如所示轻松地重写代码。

If you want such a nonstandard behaviour, maybe try to look at Scala language, for example. 如果您想要这种非标准的行为,例如,可以尝试查看Scala语言。 You'll be able to create truly monstrous control structures there. 您将能够在那里创建真正可怕的控制结构。

This : 这个 :

for (int y = 0; E elem : list; y++) {
   process(elem, y);
}

can very well be written as this : 可以这样写:

E elem;
for (int y = 0 ; y < list.size(); y++, elem = list.get(y)) {
    process(elem, y);
}

Though the scope of the variable elem differs in this case . 尽管在这种情况下变量elem的范围有所不同。 Hence I don't think there is an explicit need for the 3rd option , again , opinions may vary . 因此,我认为没有明显的选择第三选择的可能,意见可能会有所不同。

In a language like Python, this could be solved by zipping with an integer sequence: 在像Python这样的语言中,这可以通过以整数序列压缩来解决:

>>> a = ['a','b','c','d']
>>> for val,i in zip(a, range(len(a))):
...   print val, i
...
a 0
b 1
c 2
d 3

Obviously Java doesn't have syntactic support for something like this, but I do think there can be good reasons for avoiding calling list.get(i) on each iteration, not least that fetching a specific value might be much slower than iterating to the next value (say, with a linked list). 显然,Java对此不提供语法支持,但是我确实认为有充分的理由避免在每次迭代中都调用list.get(i) ,不仅如此,获取特定值可能比迭代到它慢得多。下一个值(例如,带有链表)。

I'm not a fan of departing from convention when using loop syntax, so I'm not so keen on putting different variables in the test and increment portions of a normal for-loop (Alexei Kaigorodov's solution looks nice, but potentially confusing for people who aren't familiar with it). 我不喜欢在使用循环语法时偏离约定,因此我不太热衷于在常规for循环的测试和增量部分中放置不同的变量(Alexei Kaigorodov的解决方案看起来不错,但可能会使人感到困惑谁不熟悉)。 My usuallly-preferred solution is to maintain the count separately while using a for-each loop, which is the OP's Option 2. 我通常首选的解决方案是在使用for-each循环(这是OP的选项2)时分别维护计数。

Alternatively, you could use my CountingIterable<> class, which provides the count as well as the value. 或者,您可以使用我的CountingIterable <>类,该类提供计数和值。 Whether this is a good idea in production code is still up for debate, but the question inspired me to write it and stick it on Github . 在生产代码中这是否是一个好主意尚有待商debate,但这个问题激发了我编写并将其粘贴在Github上的疑问。

It's used like this: 它的用法如下:

for (Counted<E> v : counting(iterable)) {
    process(v.getValue(), v.getCount());
}

(Where, in the code this was taken from, counting is statically imported from the Counting class) (在此代码中, counting是从Counting类静态导入的)

I believe this is an opinion based question. 我相信这是一个基于意见的问题。 Only the language designers could answer that. 只有语言设计师才能回答这个问题。

You could somewhat improve the Iterator syntax with a utility class, if you are willing to accept the creation of a new object that wraps Iterator to make the index available. 如果您愿意接受创建一个包装了Iterator的新对象以使索引可用的方法,则可以通过实用工具类对Iterator语法进行某种程度的改进。 See an example below: 请参阅以下示例:

public static void main(String[] args) {
    List<String> list = Arrays.asList( new String[] {"item1", "item2", "item3"} );

    for (IndexIterator<String> it = IndexIterator.of(list.iterator()); it.hasNext();) {
        System.out.println( it.next() + " : " + it.index() );
    }
    // Prints:
    // item1 : 0
    // item2 : 1
    // item3 : 2
}

The IndexIterator utility class is as follows: IndexIterator实用程序类如下:

public static class IndexIterator<T> implements Iterator<T> {
    private int index = -1;
    private Iterator<T> iterator;
    public IndexIterator(Iterator<T> it) {
        this.iterator = it;
    }

    @Override
    public boolean hasNext() {
        return iterator.hasNext();
    }

    @Override
    public T next() {
        index++;
        return iterator.next();
    }

    @Override
    public void remove() {
        iterator.remove();
    }

    public int index() {
        return this.index;
    }

    public static <T> IndexIterator<T> of(Iterator<T> it) {
        return new IndexIterator<T>(it);
    }
}

Isn't 是不是

nextIndex() 

what you are looking for instead of y? 您在寻找什么而不是y? Ps using ListIterator 使用ListIterator的PS

Edited: this is what I meant in code: 编辑:这就是我在代码中的意思:

Iterator<E> it = list.iterator();
while (it.hasNext()){
    process(it.next(), it.previousIndex());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM