首页 > 解决方案 > 我如何遍历对象的 LinkedHashSet?

问题描述

我有一个对象的 LinkedHashSet(每个对象有 3 个实例变量),我需要对每个对象进行操作并处理字段。我怎样才能遍历它?我的猜测是我需要使用迭代器,但我不知道该怎么做。

标签: javaset

解决方案


目前有 3 种主要方法可以遍历集合,但是类必须实现java.lan.Iterable接口。如果是这样,我们可以这样做:

常见for-each循环:

假设一组Set<Object> set = new LinkedHashSet<>();填充了随机对象并且我们想要打印,那么我们可以使用for-each循环:

for ( Object o : set )
{
  // o is the reference to the currently selected object
  System.out.println(o);
  processObject( o );
}

此循环将依次选择集合中的每个对象并按照正文中的定义对其进行处理。这个特定的循环将它打印到标准输出流,然后将对象传递给processObject(Object o)方法。由于这只是一个示例,该方法除了再次打印该值之外什么也不做。由于此循环按顺序执行,因此在“选择”下一个对象之前,每个对象都会被完全处理。for-each
循环 的一个主要缺点是我们无法在迭代期间安全地从集合中删除任何项目。

错误的例子:

// Doing so will lead to a ConcurrentModificationException being thrown
for ( Object o : set )
{
  set.remove( o );
}

然而,for-each循环可以用另一种方式表示。

迭代器循环:

安静类似于Suryakant Bhartis 的答案,我们这次java.util.Iterator在这个例子中使用:

// Utilizing the iterator provided by Set#iterator()
for ( Iterator<Object> iter = set.iterator(); iter.hasNext(); /* empty*/ )
{
  // Iterator#next() returns the next object in line.
  Object o = iter.next();
  System.out.println( o );
  processObject( o );
}

for(int i = 0; i < n;i++){}Iterator是在 for 循环中直接声明和初始化的,整体结构与“普通”循环(这是因为迭代器有一个内部计数器和指向下一个对象的指针,该对象通过调用iterator#next(). 但是,当多个操作需要同一个对象时,我们必须首先将其存储在局部变量中,因为后续调用Iterator#next()将导致不同的结果,或者NoSuchElementException如果集合中没有更多元素。
假设我们只是想将我们的集合对象传递给processObject样板代码归结为的方法:

for ( Iterator<Object> iter = set.iterator(); iter.hasNext(); )
{
  processObject( iter.next() );
}

Iterator 的一个主要好处是,如果我们不再需要/不希望它们在我们的集合中,如果使用的 Iterator 支持它,我们可以从集合中删除它们,否则UnsupportedOperationException抛出一个。

因此,让我们看一下删除该项目。为此,我们假设我们的集合仅包含 Integer 值,因此 Iterator 返回 Integer 值:

for ( Iterator<Integer> iter = set.iterator(); iter.hasNext(); )
{
  // if the returned vlaue equals 3...
  if ( iter.next().intValue() == 3 )
  {
    // ... we remove it from the set 
    iter.remove();
  }
}

请注意,此操作将删除迭代器的返回对象,而不是下一个。

Java8 流、Lambda 和方法参考。

从 Java 8(JDK 1.8 或更高版本)开始,我们能够在集合 API 的任何类上调用流,这些类遍历整个内容并能够评估所需的任何内容。让我们快速浏览一些可能的操作:

// Invoke the stream and then print every object to the standard output stream
set.stream().forEach( System.out::println );
// A 'shortcut' for the above
set.forEach( Test::processObject );
// Safely removing objects from the set. (Also a 'shortcut').
set.removeIf( i -> i.intValue() == 3 );

然而,这些有点复杂,因为大多数迭代都被混淆了。因此建议按照这样的教程完全理解上面的内容。也不建议初学者使用。


推荐阅读