java中增强for循环的最后一次迭代
Posted
技术标签:
【中文标题】java中增强for循环的最后一次迭代【英文标题】:Last iteration of enhanced for loop in java 【发布时间】:2010-09-22 01:56:15 【问题描述】:有没有办法确定循环是否是最后一次迭代。我的代码如下所示:
int[] array = 1, 2, 3...;
StringBuilder builder = new StringBuilder();
for(int i : array)
builder.append("" + i);
if(!lastiteration)
builder.append(",");
现在问题是我不想在最后一次迭代中附加逗号。现在有没有办法确定它是最后一次迭代,还是我坚持使用 for 循环或使用外部计数器来跟踪。
【问题讨论】:
是的!很有趣,我只是想问完全相同的问题! 同样的问题会回来(而且会如此)。现在,如果一个元素需要不同的处理,为什么要创建一个循环? ***.com/questions/156650/… 既然你有一个固定的数组,为什么要使用增强型呢? for(int i = 0; i 【参考方案1】:总是追加可能更容易。然后,当您完成循环后,只需删除最后一个字符。这样也少了很多条件。
您可以使用StringBuilder
的deleteCharAt(int index)
,索引为length() - 1
【讨论】:
这个问题最有效的解决方案。 +1。 也许是我,但我真的不喜欢你正在删除你刚刚添加的东西...... Fortega:我不喜欢每次都检查我 99% 都会做的事情。应用 Dinah 或 sblundy 的解决方案似乎更合乎逻辑(而且速度更快)。 我认为最优雅的解决方案。谢谢!【参考方案2】:如果你把它转换成一个经典的索引循环,是的。
或者您可以在完成后删除最后一个逗号。像这样:
int[] array = 1, 2, 3...;
StringBuilder
builder = new StringBuilder();
for(int i : array)
builder.append(i + ",");
if(builder.charAt((builder.length() - 1) == ','))
builder.deleteCharAt(builder.length() - 1);
我,我只是使用commons-lang 中的StringUtils.join()
。
【讨论】:
【参考方案3】:保持简单并使用标准的 for 循环:
for(int i = 0 ; i < array.length ; i ++ )
builder.append(array[i]);
if( i != array.length - 1 )
builder.append(',');
或者只使用 apache commons-lang StringUtils.join()
【讨论】:
【参考方案4】:显式循环总是比隐式循环更好。
builder.append( "" + array[0] );
for( int i = 1; i != array.length; i += 1 )
builder.append( ", " + array[i] );
您应该将整个内容包装在一个 if 语句中,以防万一您正在处理一个零长度数组。
【讨论】:
我喜欢这种方法,因为它不需要在每次迭代中执行测试。我唯一要补充的是builder可以直接附加整数,因此不需要使用“”+ int,只需附加(数组[0])。 如果围绕整个批次,您还需要一个以确保数组至少包含一个元素。 为什么每个人都在 append 的内部继续使用字符串连接的示例? ", " + x 编译成 new StringBuilder(", ").append( x ).toString()... @Josh 和@John:按照 n00b 示例。不想一次介绍太多东西。但是,您的观点非常好。 @Tom:对。我想我已经说过了。无需修改。【参考方案5】:另一种选择是在附加 i 之前附加逗号,而不是在 first 迭代中。 (顺便说一句,请不要使用"" + i
- 你真的不想在这里进行连接,而且 StringBuilder 有一个非常好的 append(int) 重载。)
int[] array = 1, 2, 3...;
StringBuilder builder = new StringBuilder();
for (int i : array)
if (builder.length() != 0)
builder.append(",");
builder.append(i);
这样做的好处是它可以与任何Iterable
一起使用——你不能总是索引东西。 (当您真正使用 StringBuilder 时,“添加逗号然后在末尾删除它”是一个不错的建议 - 但它不适用于写入流之类的事情。不过,这可能是解决这个确切问题的最佳方法。 )
【讨论】:
很好的模式,但是 builder.length() != 0 很脆弱——想象一下在循环之前将某些东西(有条件地!)添加到缓冲区中。相反,请使用isFirst
布尔标志。奖励:也更快。
@Jason:我当然使用“isFirst”模式,其中构建器在第一次迭代时不会为空。但是,根据我的经验,当不需要它时,它会给实现增加相当多的臃肿。
@Liverpool (etc):1000 次不必要的检查非常,非常不太可能对性能产生任何重大影响。我可能同样指出,Dinah 的解决方案添加的额外字符 可能 导致 StringBuilder 必须扩展,最终字符串的大小加倍 (cont)
不必要的缓冲空间。然而,重要的一点是可读性。我碰巧发现我的版本比 Dinah 的更具可读性。如果你有相反的感觉,那很好。在发现瓶颈后,我只会考虑不必要的“ifs”对性能的影响。
另外,我的解决方案是一个更普遍适用的解决方案,因为它只依赖于能够写。您可以采用我的解决方案并将其更改为写入流等 - 之后您可能无法取回不必要的数据。我喜欢普遍适用的模式。【参考方案6】:
另一种方法是将数组的长度(如果可用)存储在单独的变量中(比每次重新检查长度更有效)。然后,您可以将索引与该长度进行比较,以确定是否添加最后一个逗号。
编辑:另一个考虑因素是权衡删除最终字符(可能导致字符串复制)与在每次迭代中检查条件的性能成本。
【讨论】:
删除最后一个字符不应导致复制字符串。 StringBuffer 的 delete/deleteCharAt 方法最终调用 System 类中相同的源和目标数组中的以下方法: System -> public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);【参考方案7】:这里有一个解决方案:
int[] array = 1, 2, 3...;
StringBuilder builder = new StringBuilder();
bool firstiteration=true;
for(int i : array)
if(!firstiteration)
builder.append(",");
builder.append("" + i);
firstiteration=false;
寻找第一次迭代 :)
【讨论】:
【参考方案8】:这里有两条替代路径:
1:Apache Commons String Utils
2:保留一个名为 first
的布尔值,设置为 true。在每次迭代中,如果first
为假,则附加逗号;之后,将first
设置为 false。
【讨论】:
1) 链接失效 2) 我花了更长的时间阅读描述而不是代码:)【参考方案9】:也许您在作业中使用了错误的工具。
这比你正在做的更手动,但它在某种程度上更优雅,如果不是有点“老派”
StringBuffer buffer = new StringBuffer();
Iterator iter = s.iterator();
while (iter.hasNext())
buffer.append(iter.next());
if (iter.hasNext())
buffer.append(delimiter);
【讨论】:
【参考方案10】:另一种解决方案(也许是最有效的)
int[] array = 1, 2, 3;
StringBuilder builder = new StringBuilder();
if (array.length != 0)
builder.append(array[0]);
for (int i = 1; i < array.length; i++ )
builder.append(",");
builder.append(array[i]);
【讨论】:
这是一个自然的解决方案,只是它依赖于数组不为空。 @orcmid:如果数组是空的,那么这仍然会给出正确的输出——一个空字符串。我不确定你的意思是什么。【参考方案11】:另一种方法:
String delim = "";
for (int i : ints)
sb.append(delim).append(i);
delim = ",";
更新:对于 Java 8,您现在拥有 Collectors
【讨论】:
不得不删除我的类似答案 - 这将教会我在更仔细地查看其他答案之前不要发布。 另请注意,这可以处理 Robert Paulson 在另一个评论线程中提到的潜在问题 - 此技术不依赖于在附加数组值时 StringBuilder 为空。 虽然代码更流畅/整洁/有趣,但不如if版本明显。始终使用更明显/可读的版本。 @Bill:这不是一个硬性规定;有时“聪明”的解决方案是“更正确”的解决方案。更重要的是,你真的认为这个版本很难阅读吗?无论哪种方式,维护人员都需要逐步完成 - 我认为差异并不显着。 尽管您写入文件系统的写入调用等其他资源,但它仍然有效。好主意。【参考方案12】:如果您只是将数组转换为逗号分隔的数组,许多语言都有专门的连接函数。它将一个数组变成一个字符串,每个元素之间都有一个分隔符。
【讨论】:
【参考方案13】:你需要Class Separator。
Separator s = new Separator(", ");
for(int i : array)
builder.append(s).append(i);
Separator
类的实现很简单。它包装了一个字符串,该字符串在每次调用 toString()
时返回,但第一次调用除外,它返回一个空字符串。
【讨论】:
【参考方案14】:基于java.util.AbstractCollection.toString(),提前退出以避免分隔符。
StringBuffer buffer = new StringBuffer();
Iterator iter = s.iterator();
for (;;)
buffer.append(iter.next());
if (! iter.hasNext())
break;
buffer.append(delimiter);
它高效而优雅,但不像其他一些答案那样不言而喻。
【讨论】:
(! i.hasNext())
时忘记包含早期返回,这是整体方法稳健性的重要组成部分。 (这里的其他解决方案可以优雅地处理空集合,所以你也应该这样做!:)【参考方案15】:
另一种选择。
StringBuilder builder = new StringBuilder();
for(int i : array)
builder.append(',').append(i);
String text = builder.toString();
if (text.startsWith(",")) text=text.substring(1);
【讨论】:
我在另一个问题上做了修改【参考方案16】:这几乎是this *** question 的重复。你想要的是 StringUtils,并调用 join 方法。
StringUtils.join(strArr, ',');
【讨论】:
【参考方案17】:这里描述的许多解决方案有点过头了,恕我直言,尤其是那些依赖外部库的解决方案。有一个很好的干净、清晰的习惯用法来实现我一直使用的逗号分隔列表。它依赖于条件 (?) 运算符:
编辑:原始解决方案正确,但根据 cmets 不是最佳的。第二次尝试:
int[] array = 1, 2, 3;
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < array.length; i++)
builder.append(i == 0 ? "" : ",").append(array[i]);
到此为止,只需 4 行代码,包括数组的声明和 StringBuilder。
【讨论】:
但是您在每次迭代时都会创建一个新的 StringBuilder(感谢 + 运算符)。 是的,如果您查看字节码,您是对的。我不敢相信这么简单的问题会变得如此复杂。不知编译器能不能在这里优化。 提供了第二个,希望是更好的解决方案。【参考方案18】:在这种情况下,真的不需要知道它是否是最后一次重复。 我们有很多方法可以解决这个问题。一种方法是:
String del = null;
for(int i : array)
if (del != null)
builder.append(del);
else
del = ",";
builder.append(i);
【讨论】:
【参考方案19】:这是我运行的 SSCCE 基准测试(与我必须实施的相关),结果如下:
elapsed time with checks at every iteration: 12055(ms)
elapsed time with deletion at the end: 11977(ms)
至少在我的示例中,在每次迭代时跳过检查并不明显更快,尤其是对于正常的数据量,但它更快。
import java.util.ArrayList;
import java.util.List;
public class TestCommas
public static String GetUrlsIn(int aProjectID, List<String> aUrls, boolean aPreferChecks)
if (aPreferChecks)
StringBuffer sql = new StringBuffer("select * from mytable_" + aProjectID + " WHERE hash IN ");
StringBuffer inHashes = new StringBuffer("(");
StringBuffer inURLs = new StringBuffer("(");
if (aUrls.size() > 0)
for (String url : aUrls)
if (inHashes.length() > 0)
inHashes.append(",");
inURLs.append(",");
inHashes.append(url.hashCode());
inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"");//.append(",");
inHashes.append(")");
inURLs.append(")");
return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
else
StringBuffer sql = new StringBuffer("select * from mytable" + aProjectID + " WHERE hash IN ");
StringBuffer inHashes = new StringBuffer("(");
StringBuffer inURLs = new StringBuffer("(");
if (aUrls.size() > 0)
for (String url : aUrls)
inHashes.append(url.hashCode()).append(",");
inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"").append(",");
inHashes.deleteCharAt(inHashes.length()-1);
inURLs.deleteCharAt(inURLs.length()-1);
inHashes.append(")");
inURLs.append(")");
return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
public static void main(String[] args)
List<String> urls = new ArrayList<String>();
for (int i = 0; i < 10000; i++)
urls.add("http://www.google.com/" + System.currentTimeMillis());
urls.add("http://www.yahoo.com/" + System.currentTimeMillis());
urls.add("http://www.bing.com/" + System.currentTimeMillis());
long startTime = System.currentTimeMillis();
for (int i = 0; i < 300; i++)
GetUrlsIn(5, urls, true);
long endTime = System.currentTimeMillis();
System.out.println("elapsed time with checks at every iteration: " + (endTime-startTime) + "(ms)");
startTime = System.currentTimeMillis();
for (int i = 0; i < 300; i++)
GetUrlsIn(5, urls, false);
endTime = System.currentTimeMillis();
System.out.println("elapsed time with deletion at the end: " + (endTime-startTime) + "(ms)");
【讨论】:
请不要推出自己的基准测试并使用OpenJDKs own micro benchmarking harness (jmh)。它将预热您的代码并避免最有问题的陷阱。【参考方案20】:正如工具包所述,在 Java 8 中,我们现在拥有 Collectors。代码如下所示:
String joined = array.stream().map(Object::toString).collect(Collectors.joining(", "));
我认为这正是您正在寻找的,并且它是您可以用于许多其他事情的模式。
【讨论】:
【参考方案21】:由于它是一个固定数组,因此更容易避免增强 for... 如果 Object 是一个集合,则迭代器会更容易。
int nums[] = getNumbersArray();
StringBuilder builder = new StringBuilder();
// non enhanced version
for(int i = 0; i < nums.length; i++)
builder.append(nums[i]);
if(i < nums.length - 1)
builder.append(",");
//using iterator
Iterator<int> numIter = Arrays.asList(nums).iterator();
while(numIter.hasNext())
int num = numIter.next();
builder.append(num);
if(numIter.hasNext())
builder.append(",");
【讨论】:
【参考方案22】:您可以使用StringJoiner。
int[] array = 1, 2, 3 ;
StringJoiner stringJoiner = new StringJoiner(",");
for (int i : array)
stringJoiner.add(String.valueOf(i));
System.out.println(stringJoiner);
【讨论】:
以上是关于java中增强for循环的最后一次迭代的主要内容,如果未能解决你的问题,请参考以下文章