下面列出了java.util.ListIterator#remove ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public synchronized void remove (String pkey, AuthCacheValue entry) {
LinkedList<AuthCacheValue> list = hashtable.get (pkey);
if (list == null) {
return;
}
if (entry == null) {
list.clear();
return;
}
ListIterator<AuthCacheValue> iter = list.listIterator ();
while (iter.hasNext()) {
AuthenticationInfo inf = (AuthenticationInfo)iter.next();
if (entry.equals(inf)) {
iter.remove ();
}
}
}
/**
* Tests remove on list iterator is correct.
*/
public void testListListIteratorNextRemoveNext() {
if (isRemoveSupported() == false)
return;
resetFull();
if (collection.size() < 4)
return;
ListIterator it = getList().listIterator();
Object zero = it.next();
Object one = it.next();
Object two = it.next();
assertEquals(zero, getList().get(0));
assertEquals(one, getList().get(1));
assertEquals(two, getList().get(2));
Object three = getList().get(3);
it.remove(); // removed element at index 2 (two)
assertEquals(zero, getList().get(0));
assertEquals(one, getList().get(1));
Object three2 = it.next(); // do next after remove
assertEquals(three, three2);
assertEquals(collection.size() > 3, it.hasNext());
assertEquals(true, it.hasPrevious());
}
private Job getNextAvailableJob() {
if (jobQueue.isEmpty()) return null;
ListIterator<Job> iterator = jobQueue.listIterator();
while (iterator.hasNext()) {
Job job = iterator.next();
if (job.isRequirementsMet() && isGroupIdAvailable(job)) {
iterator.remove();
setGroupIdUnavailable(job);
return job;
}
}
return null;
}
/**
* App started in VA may be removed in OverView screen, then AMS.removeTask
* will be invoked, all data struct about the task in AMS are released,
* while the client's process is still alive. So remove related data in VA
* as well. A new TaskRecord will be recreated in `onActivityCreated`
*/
private void optimizeTasksLocked() {
// noinspection deprecation
ArrayList<ActivityManager.RecentTaskInfo> recentTask = new ArrayList<>(mAM.getRecentTasks(Integer.MAX_VALUE,
ActivityManager.RECENT_WITH_EXCLUDED | ActivityManager.RECENT_IGNORE_UNAVAILABLE));
int N = mHistory.size();
while (N-- > 0) {
TaskRecord task = mHistory.valueAt(N);
ListIterator<ActivityManager.RecentTaskInfo> iterator = recentTask.listIterator();
boolean taskAlive = false;
while (iterator.hasNext()) {
ActivityManager.RecentTaskInfo info = iterator.next();
if (info.id == task.taskId) {
taskAlive = true;
iterator.remove();
break;
}
}
if (!taskAlive) {
mHistory.removeAt(N);
}
}
}
public synchronized void threadSafeRemove(@NonNull final IThreadSafeConditions<T> conditions) {
if (conditions == null) {
throw new IllegalArgumentException("conditions cannot be null");
}
/*
* Remove everything except PivotsRV
*
* Use iterator to avoid ConcurrentModificationException
*/
ListIterator<T> iterator = getList().listIterator();
final Stack<Integer> positions = new Stack<>();
int position;
T item;
while (iterator.hasNext()) {
position = iterator.nextIndex();
item = iterator.next();
if (conditions.removeIf(item)) {
iterator.remove();
positions.push(position);
}
}
conditions.onItemsRemoved(positions);
}
private void checkGrantees(GranteeIterator granteeIter,
String... expectedGrantees) {
LinkedList<String> expected = new LinkedList<String>(
Arrays.asList(expectedGrantees));
while (granteeIter.hasNext()) {
String grantee = granteeIter.next();
String group = granteeIter.getCurrentLdapGroup();
ListIterator<String> expectedIter = expected.listIterator();
while (expectedIter.hasNext()) {
String expectedGrantee = expectedIter.next();
String expectedGroup = expectedIter.next();
if (grantee.equals(expectedGrantee) && ArrayUtils.objectEquals(
granteeIter.getCurrentLdapGroup(), expectedGroup)) {
// indicates match found
grantee = null;
expectedIter.previous();
expectedIter.previous();
expectedIter.remove();
expectedIter.next();
expectedIter.remove();
break;
}
}
if (grantee != null) {
Assert.fail("Failed to find grantee=" + grantee + " group=" + group
+ " among expected: " + expected);
}
}
if (!expected.isEmpty()) {
Assert.fail("No match found for expected elements: " + expected);
}
}
public static void replaceVarsInList(Map<Var, Arg> replacements,
List<Var> vars, boolean removeDupes, boolean removeMapped) {
// Remove new duplicates
ArrayList<Var> alreadySeen = null;
if (removeDupes) {
alreadySeen = new ArrayList<Var>(vars.size());
}
ListIterator<Var> it = vars.listIterator();
while (it.hasNext()) {
Var v = it.next();
if (replacements.containsKey(v)) {
Arg oa = replacements.get(v);
if (oa.isVar()) {
if (removeDupes && alreadySeen.contains(oa.getVar())) {
it.remove();
} else {
it.set(oa.getVar());
if (removeDupes) {
alreadySeen.add(oa.getVar());
}
}
}
} else {
if (removeDupes) {
if (alreadySeen.contains(v)) {
it.remove();
} else {
alreadySeen.add(v);
}
}
}
}
}
@Override
public Progress process(Processing processing) {
ListIterator<DocumentOperation> it = processing.getDocumentOperations().listIterator();
while (it.hasNext()) {
DocumentOperation op = it.next();
String id = op.getId().toString();
if ("id:nodocstatus:foo::put:to:put".equals(id)) {
Document doc = ((DocumentPut)op).getDocument();
doc.setFieldValue("foostring", new StringFieldValue("banana"));
} else if ("id:nodocstatus:foo::put:to:remove".equals(id)) {
it.set(new DocumentRemove(new DocumentId(id)));
} else if ("id:nodocstatus:foo::put:to:update".equals(id)) {
it.set(new DocumentUpdate(getType(), id));
} else if ("id:nodocstatus:foo::put:to:nothing".equals(id)) {
it.remove();
} else if ("id:nodocstatus:foo::remove:to:put".equals(id)) {
it.set(new DocumentPut(getType(), op.getId()));
} else if ("id:nodocstatus:foo::remove:to:remove".equals(id)) {
//nada
} else if ("id:nodocstatus:foo::remove:to:update".equals(id)) {
it.set(new DocumentUpdate(getType(), id));
} else if ("id:nodocstatus:foo::remove:to:nothing".equals(id)) {
it.remove();
} else if ("id:nodocstatus:foo::update:to:put".equals(id)) {
it.set(new DocumentPut(getType(), op.getId()));
} else if ("id:nodocstatus:foo::update:to:remove".equals(id)) {
it.set(new DocumentRemove(new DocumentId(id)));
} else if ("id:nodocstatus:foo::update:to:update".equals(id)) {
//nada
} else if ("id:nodocstatus:foo::update:to:nothing".equals(id)) {
it.remove();
} else if ("id:12345:6789:multiop:nodocstatus:keep:this".equals(id)) {
//nada
}
}
return Progress.DONE;
}
/**
* Filter out the put entries and only get the delete entries.
* @param messageEntries The message entry list from which only delete entries have to be returned.
*/
private void filterDeleteEntries(List<MessageInfo> messageEntries) {
ListIterator<MessageInfo> messageEntriesIterator = messageEntries.listIterator();
/* Note: Ideally we should also filter out duplicate delete entries here. However, due to past bugs,
there could be multiple delete entries in the index for the same blob. At the cost of possibly
duplicating the effort for those rare cases, we ensure as much deletes are covered as possible.
*/
while (messageEntriesIterator.hasNext()) {
if (!messageEntriesIterator.next().isDeleted()) {
messageEntriesIterator.remove();
}
}
}
public static
void main(String[] args) {
LinkedList list = new LinkedList();
ListIterator e = list.listIterator();
Object o = new Integer(1);
e.add(o);
e.previous();
e.next();
e.remove();
e.add(o);
if (!o.equals(list.get(0)))
throw new RuntimeException("LinkedList ListIterator remove failed.");
}
private boolean havePermissions(ArrayList<String> permissions)
{
boolean allGranted = true;
ListIterator<String> it = permissions.listIterator();
while (it.hasNext()) {
if (ActivityCompat.checkSelfPermission(this, it.next()) != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
}
else {
// permission granted, remove it from permissions
it.remove();
}
}
return allGranted;
}
/** 移除一条数据 */
public void removeItem(T item) {
int position = 0;
ListIterator<T> iterator = mDatas.listIterator();
while (iterator.hasNext()) {
T next = iterator.next();
if (next == item) {
iterator.remove();
notifyItemRemoved(position);
}
position++;
}
}
/**
* Releases for normal dispatching to the current focus owner all
* KeyEvents which were enqueued because of a call to
* <code>enqueueKeyEvents</code> with the same timestamp and Component.
* If the given timestamp is less than zero, the outstanding enqueue
* request for the given Component with the <b>oldest</b> timestamp (if
* any) should be cancelled.
*
* @param after the timestamp specified in the call to
* <code>enqueueKeyEvents</code>, or any value < 0
* @param untilFocused the Component specified in the call to
* <code>enqueueKeyEvents</code>
* @see #enqueueKeyEvents
* @see #discardKeyEvents
*/
protected synchronized void dequeueKeyEvents(long after,
Component untilFocused) {
if (untilFocused == null) {
return;
}
if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
focusLog.finer("Dequeue at {0} for {1}",
after, untilFocused);
}
TypeAheadMarker marker;
ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator
((after >= 0) ? typeAheadMarkers.size() : 0);
if (after < 0) {
while (iter.hasNext()) {
marker = iter.next();
if (marker.untilFocused == untilFocused)
{
iter.remove();
return;
}
}
} else {
while (iter.hasPrevious()) {
marker = iter.previous();
if (marker.untilFocused == untilFocused &&
marker.after == after)
{
iter.remove();
return;
}
}
}
}
/**
* Filters the given model.
*
* @param filter
* @param models
*/
private static void filterTags(OASFilter filter, List<Tag> models) {
if (models != null) {
ListIterator<Tag> iterator = models.listIterator();
while (iterator.hasNext()) {
Tag model = iterator.next();
model = filter.filterTag(model);
if (model == null) {
iterator.remove();
}
}
}
}
/**
* Releases for normal dispatching to the current focus owner all
* KeyEvents which were enqueued because of a call to
* <code>enqueueKeyEvents</code> with the same timestamp and Component.
* If the given timestamp is less than zero, the outstanding enqueue
* request for the given Component with the <b>oldest</b> timestamp (if
* any) should be cancelled.
*
* @param after the timestamp specified in the call to
* <code>enqueueKeyEvents</code>, or any value < 0
* @param untilFocused the Component specified in the call to
* <code>enqueueKeyEvents</code>
* @see #enqueueKeyEvents
* @see #discardKeyEvents
*/
protected synchronized void dequeueKeyEvents(long after,
Component untilFocused) {
if (untilFocused == null) {
return;
}
focusLog.finer("Dequeue at {0} for {1}",
after, untilFocused);
TypeAheadMarker marker;
ListIterator iter = typeAheadMarkers.listIterator
((after >= 0) ? typeAheadMarkers.size() : 0);
if (after < 0) {
while (iter.hasNext()) {
marker = (TypeAheadMarker)iter.next();
if (marker.untilFocused == untilFocused)
{
iter.remove();
return;
}
}
} else {
while (iter.hasPrevious()) {
marker = (TypeAheadMarker)iter.previous();
if (marker.untilFocused == untilFocused &&
marker.after == after)
{
iter.remove();
return;
}
}
}
}
/**
* Look for single edits surrounded on both sides by equalities
* which can be shifted sideways to align the edit to a word boundary.
* e.g: The c<ins>at c</ins>ame. -> The <ins>cat </ins>came.
* @param diffs LinkedList of Diff objects.
*/
public void diff_cleanupSemanticLossless(LinkedList<Diff> diffs) {
String equality1, edit, equality2;
String commonString;
int commonOffset;
int score, bestScore;
String bestEquality1, bestEdit, bestEquality2;
// Create a new iterator at the start.
ListIterator<Diff> pointer = diffs.listIterator();
Diff prevDiff = pointer.hasNext() ? pointer.next() : null;
Diff thisDiff = pointer.hasNext() ? pointer.next() : null;
Diff nextDiff = pointer.hasNext() ? pointer.next() : null;
// Intentionally ignore the first and last element (don't need checking).
while (nextDiff != null) {
if (prevDiff.operation == Operation.EQUAL &&
nextDiff.operation == Operation.EQUAL) {
// This is a single edit surrounded by equalities.
equality1 = prevDiff.text;
edit = thisDiff.text;
equality2 = nextDiff.text;
// First, shift the edit as far left as possible.
commonOffset = diff_commonSuffix(equality1, edit);
if (commonOffset != 0) {
commonString = edit.substring(edit.length() - commonOffset);
equality1 = equality1.substring(0, equality1.length() - commonOffset);
edit = commonString + edit.substring(0, edit.length() - commonOffset);
equality2 = commonString + equality2;
}
// Second, step character by character right, looking for the best fit.
bestEquality1 = equality1;
bestEdit = edit;
bestEquality2 = equality2;
bestScore = diff_cleanupSemanticScore(equality1, edit)
+ diff_cleanupSemanticScore(edit, equality2);
while (edit.length() != 0 && equality2.length() != 0
&& edit.charAt(0) == equality2.charAt(0)) {
equality1 += edit.charAt(0);
edit = edit.substring(1) + equality2.charAt(0);
equality2 = equality2.substring(1);
score = diff_cleanupSemanticScore(equality1, edit)
+ diff_cleanupSemanticScore(edit, equality2);
// The >= encourages trailing rather than leading whitespace on edits.
if (score >= bestScore) {
bestScore = score;
bestEquality1 = equality1;
bestEdit = edit;
bestEquality2 = equality2;
}
}
if (!prevDiff.text.equals(bestEquality1)) {
// We have an improvement, save it back to the diff.
if (bestEquality1.length() != 0) {
prevDiff.text = bestEquality1;
} else {
pointer.previous(); // Walk past nextDiff.
pointer.previous(); // Walk past thisDiff.
pointer.previous(); // Walk past prevDiff.
pointer.remove(); // Delete prevDiff.
pointer.next(); // Walk past thisDiff.
pointer.next(); // Walk past nextDiff.
}
thisDiff.text = bestEdit;
if (bestEquality2.length() != 0) {
nextDiff.text = bestEquality2;
} else {
pointer.remove(); // Delete nextDiff.
nextDiff = thisDiff;
thisDiff = prevDiff;
}
}
}
prevDiff = thisDiff;
thisDiff = nextDiff;
nextDiff = pointer.hasNext() ? pointer.next() : null;
}
}
/**
* Get the DDL queue after pre-processing like pushing system procedures, jar
* procedures at the start, removing local DDLs etc.
*/
public List<GfxdDDLQueueEntry> getPreprocessedDDLQueue(
final List<GfxdDDLQueueEntry> currentQueue,
final Map<DDLConflatable, DDLConflatable> skipRegionInit,
String currentSchema, TObjectIntHashMap pre11TableSchemaVer,
boolean traceConflation) {
// push all system procedures at the start of queue since they may change
// the behaviour of the system which can be required for DDLs etc.
final ArrayList<GfxdDDLQueueEntry> preprocessedQueue =
new ArrayList<GfxdDDLQueueEntry>();
ListIterator<GfxdDDLQueueEntry> iter = currentQueue.listIterator();
GfxdDDLPreprocess preprocessMsg;
if (currentSchema == null) {
currentSchema = SchemaDescriptor.STD_DEFAULT_SCHEMA_NAME;
}
while (iter.hasNext()) {
final GfxdDDLQueueEntry entry = iter.next();
final Object qVal = entry.getValue();
if (qVal instanceof ReplayableConflatable) {
// remove from queue if this object is marked to be skipped
// in local execution
if (((ReplayableConflatable)qVal).skipInLocalExecution()) {
iter.remove();
continue;
}
}
// system/jar procedures should be executed at the start
if (qVal instanceof GfxdDDLPreprocess
&& (preprocessMsg = (GfxdDDLPreprocess)qVal).preprocess()) {
if (pre11TableSchemaVer != null
&& preprocessMsg instanceof GfxdSystemProcedureMessage) {
GfxdSystemProcedureMessage m = (GfxdSystemProcedureMessage)qVal;
// check for persisted PRE11_RECOVERY_SCHEMA_VERSIONs
if (m.getSysProcMethod() == GfxdSystemProcedureMessage
.SysProcMethod.setDatabaseProperty) {
Object[] params = m.getParameters();
String key = (String)params[0];
if (key != null && key.startsWith(
GfxdConstants.PRE11_RECOVERY_SCHEMA_VERSION)) {
pre11TableSchemaVer.put(key
.substring(GfxdConstants.PRE11_RECOVERY_SCHEMA_VERSION
.length()), Integer.parseInt((String)params[1]));
}
}
}
preprocessedQueue.add(entry);
iter.remove();
}
// also check if region intialization should be skipped for
// any of the regions due to ALTER TABLE (#44280)
else if (qVal instanceof DDLConflatable) {
final DDLConflatable ddl = (DDLConflatable)qVal;
if (skipRegionInit == null) {
// need to add explicit "CREATE SCHEMA" DDLs for this case if the
// schema changes
String newSchema = ddl.getCurrentSchema();
if (newSchema == null) {
newSchema = SchemaDescriptor.STD_DEFAULT_SCHEMA_NAME;
}
if (!currentSchema.equals(newSchema)) {
DDLConflatable schemaDDL = new DDLConflatable("SET SCHEMA "
+ newSchema, newSchema, new CreateSchemaConstantAction(
newSchema, null), null, null, 0, true);
final QueueValue qValue = new QueueValue(0L, new RegionValue(
schemaDDL, 0L));
iter.add(qValue);
}
currentSchema = newSchema;
}
else if (ddl.shouldDelayRegionInitialization()) {
final ArrayList<QueueValue> conflatedItems =
new ArrayList<QueueValue>(5);
if (conflate(ddl, ddl, false, conflatedItems)) {
for (QueueValue confItem : conflatedItems) {
Object confVal = confItem.getValue();
DDLConflatable createDDL;
if (confVal instanceof DDLConflatable
&& (createDDL = (DDLConflatable)confVal).isCreateTable()) {
// update the mapping for CREATE TABLE to this ALTER
skipRegionInit.put(createDDL, ddl);
if (traceConflation) {
SanityManager.DEBUG_PRINT(GfxdConstants.TRACE_CONFLATION,
"FabricDatabase: delaying initializing [" + confVal
+ "] for DDL [" + ddl + ']');
}
// expect only one CREATE TABLE at max, so break now
break;
}
}
}
}
}
}
preprocessedQueue.addAll(currentQueue);
return preprocessedQueue;
}
/**
* Inline from bottom-up
* @param mainBlock
* @param cong
*/
private void inlinePass(GlobalConstants consts, Block block,
Map<Block, Congruences> cong) {
Congruences blockState = cong.get(block);
if (blockState == null) {
// Dead code
return;
}
if (logger.isTraceEnabled()) {
logger.trace("=======================================");
logger.trace("Inlining statements on block " +
System.identityHashCode(block) + ": " + block.getType());
blockState.printTraceInfo(logger, consts);
}
// Use original statement count from when block was constructed
int origStmtCount = block.getStatements().size();
ListIterator<Statement> stmtIt = block.statementIterator();
while (stmtIt.hasNext()) {
Statement stmt = stmtIt.next();
if (stmt.type() == StatementType.CONDITIONAL) {
// First recurse
tryInlineConditional(consts, block, stmtIt, stmt.conditional(), cong);
} else {
assert(stmt.type() == StatementType.INSTRUCTION);
// Leave instructions alone
}
}
// Block state will reflect closed vars as of end of block
Set<Var> closedVars;
Set<Var> recClosedVars;
if (finalizedVarEnabled) {
recClosedVars = blockState.getRecursivelyClosed(origStmtCount);
closedVars = blockState.getClosed(origStmtCount);
} else {
recClosedVars = Collections.emptySet();
closedVars = Collections.emptySet();
}
if (logger.isTraceEnabled()) {
logger.trace("=======================================");
logger.trace("Inlining continuations on block " +
System.identityHashCode(block) + ": " + block.getType());
blockState.printTraceInfo(logger, consts);
}
ListIterator<Continuation> contIt = block.continuationIterator();
while (contIt.hasNext()) {
Continuation cont = contIt.next();
// First recurse
inlinePassRecurse(consts, cont, cong);
if (logger.isTraceEnabled()) {
logger.trace("Return to block " + System.identityHashCode(block) +
" checking " + cont.getType());
}
// Then try to inline
if (cont.isNoop()) {
logger.trace("Removed noop continuation " + cont.getType());
contIt.remove();
} else if (tryInlineContinuation(block, cont, contIt,
closedVars, recClosedVars)) {
// Success! Will now iterate over rest
logger.trace("Inlined continuation " + cont.getType());
}
}
}
/**
* Schedule function looks in the "mesosWorkerSlotMap" to determine which topology owns the particular
* WorkerSlot and assigns the executors accordingly.
*/
@Override
public void schedule(Topologies topologies, Cluster cluster) {
List<WorkerSlot> workerSlots = cluster.getAvailableSlots();
String info = "";
if (!workerSlots.isEmpty()) {
info = "Scheduling the following worker slots from cluster.getAvailableSlots: ";
List<String> workerSlotsStrings = new ArrayList<String>();
for (WorkerSlot ws : workerSlots) {
workerSlotsStrings.add(ws.toString());
}
info += String.format("[%s]", StringUtils.join(workerSlotsStrings, ", "));
log.info(info);
}
Map<String, List<MesosWorkerSlot>> perTopologySlotList = getMesosWorkerSlotPerTopology(workerSlots);
if (perTopologySlotList.isEmpty()) {
return;
}
info = "Schedule the per-topology slots:";
for (String topo : perTopologySlotList.keySet()) {
List<String> mwsAssignments = new ArrayList<>();
for (MesosWorkerSlot mws : perTopologySlotList.get(topo)) {
mwsAssignments.add(mws.getNodeId() + ":" + mws.getPort());
}
info += String.format(" {%s, [%s]}", topo, StringUtils.join(mwsAssignments, ", "));
}
log.info(info);
// So far we know how many MesosSlots each of the topologies have got. Let's assign executors for each of them
for (String topologyId : perTopologySlotList.keySet()) {
TopologyDetails topologyDetails = topologies.getById(topologyId);
List<MesosWorkerSlot> mesosWorkerSlots = perTopologySlotList.get(topologyId);
int slotsRequested = topologyDetails.getNumWorkers();
int slotsAssigned = cluster.getAssignedNumWorkers(topologyDetails);
int slotsAvailable = mesosWorkerSlots.size();
if (slotsAvailable == 0) {
log.warn("No slots found for topology {} while scheduling", topologyId);
continue;
}
log.info("topologyId: {}, slotsRequested: {}, slotsAssigned: {}, slotsAvailable: {}", topologyId, slotsRequested, slotsAssigned, slotsAvailable);
List<List<ExecutorDetails>> executorsPerWorkerList = executorsPerWorkerList(cluster, topologyDetails, slotsRequested, slotsAssigned, slotsAvailable);
if (executorsPerWorkerList == null || executorsPerWorkerList.isEmpty()) {
continue;
}
info = "schedule: Cluster assignment for " + topologyId + "."
+ " Requesting " + slotsRequested + " slots, with " + slotsAvailable + " slots available, and " + slotsAssigned + " currently assigned."
+ " Setting new assignment (node:port, executorsPerWorkerList) as: ";
List<String> slotAssignmentStrings = new ArrayList<String>();
ListIterator<List<ExecutorDetails>> iterator = executorsPerWorkerList.listIterator();
while (iterator.hasNext()) {
List<ExecutorDetails> executorsPerWorker = iterator.next();
slotAssignmentStrings.add("(" + mesosWorkerSlots.get(0).getNodeId() + ":" + mesosWorkerSlots.get(0).getPort() + ", " + executorsPerWorker.toString() + ")");
iterator.remove();
cluster.assign(mesosWorkerSlots.remove(0), topologyId, executorsPerWorker);
}
if (slotsAvailable == 0) {
info += "[]";
} else {
info += StringUtils.join(slotAssignmentStrings, ", ");
}
log.info(info);
}
mesosWorkerSlotMap.clear();
}
public void testOptimizedForEach() throws Exception {
final Integer[] data = new Integer[1000 * 1000];
for (int i=0; i < data.length; i++) {
data[i] = i;
}
final List<Integer> source = Arrays.asList(data);
final String[] listClasses = {
"java.util.ArrayList",
"java.util.LinkedList",
"java.util.Vector",
"java.util.concurrent.CopyOnWriteArrayList"
};
final int OFFSET = 3;
final List<Integer> target = new ArrayList<>(source);
for (final String listClass : listClasses) {
final List<Integer> list =
(List<Integer>) Class.forName(listClass).newInstance();
list.addAll(source);
final ListIterator<Integer> iterator = list.listIterator();
assertFalse(iterator.hasPrevious());
for (int i=0; i < OFFSET; i++) {
iterator.next();
}
assertTrue(iterator.hasNext());
assertTrue(iterator.hasPrevious());
assertEquals(iterator.nextIndex(), OFFSET);
assertEquals(iterator.previousIndex(), OFFSET - 1);
iterator.forEachRemaining(e -> {
target.set(e, e + 1);
});
for (int i=OFFSET; i < data.length; i++) {
assertEquals(target.get(i).intValue(), source.get(i)+1);
}
assertFalse(iterator.hasNext());
assertTrue(iterator.hasPrevious());
assertEquals(iterator.nextIndex(), data.length);
assertEquals(iterator.previousIndex(), data.length - 1);
// CopyOnWriteArrayList.listIterator().remove() is unsupported
if (!"java.util.concurrent.CopyOnWriteArrayList".equals(listClass)) {
for (int i = data.length - 1; i >= 0; i--) {
iterator.remove(); // must not throw
if (i > 0) {
iterator.previous();
}
}
assertTrue(list.isEmpty());
}
try {
iterator.next();
fail(listClass + " iterator advanced beyond end");
} catch (NoSuchElementException ignore) {
}
}
}