Here's a construct that will keep modified within the loop's scope, but still requires a declaration:
for (bool modified = false; modified; ) {
modified = false;
for (Object o : objectList) {
modified |= condition;
/* If "condition" involves heavy computation, prefer the type of
condition-checking in @Sazzad's answer, as this will not
short-circuit to "true" if "modified" is already true. */
}
}
Alternately, use a while loop with a label (although labels don't really belong to the OO style):
outer:
while(true) {
for (Object o : objectList) {
//do stuff
}
if(objectList.stream().anyMatch(/* condition predicate */)) {
break outer;
}
}
This will work with however many levels of nesting you have.
Here's a third solution using a do-while loop:
do {
for (Object o : objectList) {
//do stuff
}
} while (objectList.stream.anyMatch(/* predicate */));
Depending on what your condition looks like, you can make the check pretty obvious using a method reference:
objectList.stream().anyMatch(this::condition);
breakkeyword serves this purpose, although its use is controversial, as it has a definite "procedural" smell to it, and obscures the control flow. What you just wrote is quite common, and its common use makes its purpose clear to the reader.modified.modifiedhas to be declared outside the loop, but assigned a value inside the loop.