Вы можете думать, что такого особенного в циклах, что этому посвящена целая статья? Ну что ж, просто ответьте на следующий простой вопрос. Если вы сможете ответить, то можете дальше не читать. Если нет, то читайте.
Вопрос: Сколько раз будет напечатано "end(): Invoked"?
/**
* Understanding the for loop.
*/
public class ForLoopTest {
/**
* Start of loop.
*/
public int start() {
System.out.println("start(): Invoked");
return 0;
}
/**
* End of loop condition.
*/
public int end() {
System.out.println("end(): Invoked");
return 5;
}
/**
* Main.
*/
public static void main(String[] args) {
ForLoopTest fl = new ForLoopTest();
for(int i = fl.start(); i < fl.end(); i++) {
System.out.println("main(): i = " + i);
}
}
}
Я знаю, что это выглядит просто, но некоторые из вас будут удивлены, тем, что оно будет распечатано 6 раз (да-да, не 5-ть). Ну что же, эта статья так же и для тех, кто думал, что оно распечатается один раз.
Что же там произошло на самом деле:
1. Метод start() выполнился один раз для инициализации индекса.
2. До входа в цикл, метод end() отработал для проверки окончания условия.
3. С этого времени, каждая итерация вызывала метод end() во время вычисления выражения условия. И так 5 раз.
Так что, как вы видите результат, но в чем же дело? А дело заключается в том, что такой вызов метода очень дорог. Если ваш цикл совершит несколько сотен итераций вы увидите сколько вы тратите на такие циклы. С другой стороны такой стиль программирования часто используется и наиболее встречаемый пример - метод String::length().
Самое лучшее, что можно посоветовать это завести локальные переменные, в которых хранить значение выхода из цикла. Так что этот цикл должен быть переписан примерно так:
int n = end();
for (int i = start(); i < n; i++) {
// ...
}
Применение такого подхода может сохранить много времени в задачах потребляющих много времени.
Вопрос: Сколько раз будет напечатано "end(): Invoked"?
/**
* Understanding the for loop.
*/
public class ForLoopTest {
/**
* Start of loop.
*/
public int start() {
System.out.println("start(): Invoked");
return 0;
}
/**
* End of loop condition.
*/
public int end() {
System.out.println("end(): Invoked");
return 5;
}
/**
* Main.
*/
public static void main(String[] args) {
ForLoopTest fl = new ForLoopTest();
for(int i = fl.start(); i < fl.end(); i++) {
System.out.println("main(): i = " + i);
}
}
}
Я знаю, что это выглядит просто, но некоторые из вас будут удивлены, тем, что оно будет распечатано 6 раз (да-да, не 5-ть). Ну что же, эта статья так же и для тех, кто думал, что оно распечатается один раз.
Что же там произошло на самом деле:
1. Метод start() выполнился один раз для инициализации индекса.
2. До входа в цикл, метод end() отработал для проверки окончания условия.
3. С этого времени, каждая итерация вызывала метод end() во время вычисления выражения условия. И так 5 раз.
Так что, как вы видите результат, но в чем же дело? А дело заключается в том, что такой вызов метода очень дорог. Если ваш цикл совершит несколько сотен итераций вы увидите сколько вы тратите на такие циклы. С другой стороны такой стиль программирования часто используется и наиболее встречаемый пример - метод String::length().
Самое лучшее, что можно посоветовать это завести локальные переменные, в которых хранить значение выхода из цикла. Так что этот цикл должен быть переписан примерно так:
int n = end();
for (int i = start(); i < n; i++) {
// ...
}
Применение такого подхода может сохранить много времени в задачах потребляющих много времени.