Depende. Se vc só quer percorrer a lista, o for é mais direto:
for (TipoDoObjeto obj : lista) {
// faz algo com obj
}
Um Iterator permite que se façam outras operações durante o loop. Por exemplo, remover elementos enquanto itera sobre a lista:
Iterator<TipoDoObjeto> it = lista.iterator();
while (it.hasNext()) {
TipoDoObjeto obj = it.next();
if (deveRemover(obj)) {
it.remove();
}
}
Se usarmos o for, não funciona:
for (TipoDoObjeto obj: lista) {
if (deveRemover(obj)) {
lista.remove(obj);
}
}
O código acima dá erro: java.util.ConcurrentModificationException. Uma lista só pode ser modificada durante o loop se usarmos Iterator.
Quanto a necessidade de criar equals e hashCode, depende do que vc está fazendo. O primeiro serve para comparar duas instâncias e dizer se elas são iguais, o segundo é usado para quando o objeto é inserido em estruturas cujas implementações usam tabelas de hash (como HashMap, HashSet, etc - ver mais aqui).
O que acontece é que, para que tudo funcione corretamente, a recomendação é que estes dois métodos sejam implementados segundo certas regras. Mas se vc precisa ou não implementá-los, depende de como está usando a classe.