Цикл for реализован иначе, чем в других языках?

== проверяет ссылки на объекты, .equals() проверяет строковые значения.

Иногда кажется, что == сравнивает значения, потому что Java делает некоторые закулисные вещи, чтобы убедиться, что одинаковые строки в строке являются одним и тем же объектом.

Для Например:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

Но будьте осторожны с нулями!

== обрабатывает строки null в порядке, но вызов .equals() из пустой строки приведет к исключению:

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

Итак, если вы знаете, что fooString1 может но не менее очевидно, что он проверяет значение null (из Java 7):

System.out.print(Objects.equals(fooString1, "bar"));
13
задан MPelletier 30 April 2012 в 04:11
поделиться

11 ответов

Рассмотрите это:

for i:=0 to 100 do { ... }

В этом случае, мы могли заменить окончательное значение, 100, вызовом функции:

for i:=0 to final_value() do { ... }

... и final_value - функция была бы вызвана только однажды.

В C, однако:

for (int i=0; i<final_value(); ++i) // ...

... final_value - функция была бы вызвана для каждого повторения через цикл, таким образом делая его хорошей практикой, чтобы быть более подробной:

int end = final_value();
for (int i=0; i<end; ++i) // ...
29
ответ дан Magnus Hoff 30 April 2012 в 04:11
поделиться
  • 1
    Спасибо за ответ, но я пропускающий что-то или это все равно как jeb' s окончательный ответ? – Peter Taylor 4 November 2012 в 17:06

Если все, что Вы хотите, будет простым циклом подсчета, то

for (i=0; i<100; i++) dostuff();

будет прекрасен, и компилятор может оптимизировать его.

при использовании функции в продолжать части для оператора, как

for (i=0; i<strlen(s); i++) dostuff();

тогда функция будет оценена каждый раз, когда и это обычно - не хорошая идея, поскольку функциональные издержки замедлят процесс. Иногда это может замедлить Ваш процесс на грани неудобства использования.

, Если возвращаемое значение функции не изменится во время повторения, извлеките его из цикла:

slen = strlen(s);
for (i=0; i<slen; i++) dostuff();

, Но существуют времена, когда функция будет возвращать различные значения каждый вызов, и затем Вы не хотите извлеченный из цикла:

for (isread(fd, &buffer, ISFIRST);
     isstat(fd) >= 0;
     isread(fd, &buffer, ISNEXT)
{
  dostuff(buffer);
}

и Вы хотите его, оценил каждый раз. (Который является немного изобретенным примером на основе работы, которую я делаю, но она показывает потенциал).

C дает Вам необработанную способность прокрутить Ваш цикл любым путем, Вы можете. Необходимо знать, как цикл, как предполагается, работает, и Вы оптимизируете его как лучше всего, Вы можете, в зависимости от своих потребностей.

, Что последний пример, возможно, был выражен как некоторое время цикл:

isread(fd, &buffer, ISFIRST);
while (isstat(fd) >= 0)
{
  dostuff(buffer);
  isread(fd, &buffer, ISNEXT);
}

, но это не столь аккуратно, и если я использую продолжение в цикле, тогда я должен назвать итерацию isread снова. Вставление всего этого для цикла делает его более опрятным, и гарантирует, что итерацию isread называют каждым циклом.

я пишу функции низшего уровня, таким образом, они могут использоваться в для циклов как это. Это объединяет все элементы цикла с условием продолжения, таким образом, можно понять его более легко.

5
ответ дан codebunny 30 April 2012 в 04:11
поделиться
  • 1
    На самом деле, it' s та же техника. Я думаю, возможно, что я приблизился к нему немного более ясно (с целью помочь будущим программистам, которые спотыкаются через этот вопрос), но I' ll позволяют Вам быть судьей:-). – rkagerer 6 November 2012 в 01:17

Он, вероятно, обращается к для циклов как for i:=0 to N и циклы foreach, которые выполняют итерации по элементам набора. Я подозреваю все языки, которые имеют C-стиль для цикла, на самом деле получил его от C.

4
ответ дан mweerden 30 April 2012 в 04:11
поделиться
  • 1
    Вы - человек! Это - лучшее = falst + самое легкое решение, чем другие в том вопросе!!! Если я был автором вопроса, я, конечно, изменяю ответ на Ваш! – kokbira 17 March 2014 в 14:55

У Magnus есть он правильный, но нужно также отметить, что на большинстве языков (pre-C), условное выражение конец критерий (т.е. "останавливаются, когда я равняюсь 100"). В C (и большинство постязыков C), это эти , продолжаются критерий (т.е. "продолжаются, в то время как я - меньше чем 100").

3
ответ дан James Curran 30 April 2012 в 04:11
поделиться

На x86, для цикличного выполнения может быть сделан на уровне ассемблера, не делая некоторое время цикл. цикл инструкция уменьшает значение регистра ecx и переходит к операнду, если ecx больше, чем 0, это ничего не делает иначе. Это - классик для цикла.

mov ecx, 0x00000010h
loop_start:
;loop body
loop loop_start
;end of loop
2
ответ дан Tamas Czinege 30 April 2012 в 04:11
поделиться

В основном C (и Java, JavaScript и партия языков C-derived) for цикл является действительно синтаксическим сахаром для while цикл:

for (int i = 0; i < max; i++) { DoStuff(); }

то, которое является очень текущей идиомой, строго эквивалентно:

int i = 0; while (i < max) { DoStuff(); i++; }

(Помещающий независимо определяют объем проблем, которые изменились между версиями C так или иначе.)

условие остановки оценено на каждом повторении. Это может быть интересно в некоторых случаях, но это может быть ловушка: Я видел i < strlen(longConstantString) в источнике, который является главным способом замедлить программу, потому что strlen дорогостоящая функция в C.
Так или иначе, for цикл главным образом разработан для выполнения, неоднократно знают заранее, можно все еще использовать break для завершения рано, таким образом, динамическая оценка термина остановки является более раздражающей, чем полезный: при реальной необходимости в динамической оценке Вы используете while () {} (или do {} while ()).

На некоторых других языках, как Lua, условие остановки оценено только однажды в цикле init. Это помогает предсказанию поведения цикла, и это часто более производительно.

2
ответ дан PhiLho 30 April 2012 в 04:11
поделиться

Развертывание цикла, возможно? Если Вы знаете, сколько время для цикла собирается выполнить, можно буквально скопировать и вставить содержание цикла. Большинство циклов с условием продолжения будет быть основанным на некотором условии, которое не является простым подсчетом от 0 до N, так не будет в состоянии использовать эту оптимизацию.

Берут этот пример

int x;
for (x = 10; x != 0; --x)
{
    printf ("Hello\n");
}

, я знаю, что Вы обычно делали бы x = 0; x <= 10; ++x, но все будут показаны в блоке.

некоторый псевдо блок:

mov 10, eax
loop:
print "hello"
dec eax
jne loop

В этом примере мы удерживаем на месте переход вокруг цикла для печати "привет" 10 раз. Однако мы оцениваем условие с jne инструкция каждый раз вокруг цикла.

, Если бы мы развернули его, мы могли бы просто поместить

print "hello"
print "hello"
print "hello"
print "hello"
print "hello"
print "hello"
print "hello"
print "hello"
print "hello"
print "hello"

, Нам не была бы нужна ни одна из других инструкций, таким образом, это быстрее. Это - только простой пример - я попытаюсь найти лучший!

2
ответ дан Tarski 30 April 2012 в 04:11
поделиться
  • 1
    Да, это имеет смысл. Я адаптировал Joey' s подход с помощью замен " и " к пустой строке, которая более проста, но немного менее устойчива против пробельных изменений. – Peter Taylor 23 September 2011 в 07:30

В Ada (и я верю большинству других Полученных из Алгола языков) завершающееся условие "для" цикла оценено только однажды, в начале цикла. Например, предположите, что у Вас есть следующий код в Ada

q := 10;
for i in 1..q loop
    q := 20;
    --// Do some stuff
end loop;

, которого Этот цикл выполнит итерации точно 10 раз, потому что q равнялся 10 когда запущенный цикл. Однако, если я пишу на вид эквивалентный цикл в C:

q = 10;
for (int i=0;i<q;i++) {
   q = 20;
   // Do some stuff
}

Тогда цикл выполняет итерации 20 раз, потому что q был изменен на 20 к тому времени, когда я стал достаточно крупным для него для имения значение.

путь C более гибок, конечно. Однако это имеет довольно много отрицательных последствий. Очевидное - то, что программа должна потратить впустую усилие, перепроверяющее, что цикл обусловливает каждый цикл. Хороший оптимизатор мог бы быть достаточно умным для работы вокруг проблемы в простых случаях как это, но что происходит, если "q" является глобальным, и "делают некоторый материал" включает вызов процедуры (и таким образом в теории мог изменить q)?

неопровержимый факт - то, что мы просто знаем путь [еще 112] о цикле Ada, чем мы делаем о цикле C. Это означает, что с тем же уровнем аналитики и усилия в его оптимизаторе, Ada может сделать намного лучшее задание оптимизации. Например, компилятор Ada знает, что может заменить весь цикл 10 копиями содержания, неважно, каково то содержание. Оптимизатор C должен был бы исследовать и проанализировать содержание.

Это - на самом деле только один из многих путей, где дизайн синтаксиса C зажимает в тиски компилятор.

2
ответ дан T.E.D. 30 April 2012 в 04:11
поделиться

Что они, которые пурист языка никогда, кажется, не понимает, являются смыслом C, и к C++ степени, дают возможность реализовать то, что Вы хотите и как Вы хотите его. Теперь по общему признанию, если бы результат Ваших изменений конечного выражения, было бы лучше просто использовать некоторое время цикл. Возможно, проблемой являются программисты, добираются, впечатление C реализует "высокий уровень" для, но все должны знать, что C является довольно низкоуровневым языком.

1
ответ дан FredV 30 April 2012 в 04:11
поделиться
  • 1
    Это похоже на многообещающий подход, но значение I' m пытающийся добраться мог потенциально иметь пробелы в нем. I' ll пытаются идти этим путем с delims==? и затем обрезать пространство перед использованием %~. – Peter Taylor 22 September 2011 в 16:19

Возможно, Knuth относится к ОСНОВНОМУ.

В ОСНОВНОМ (более старый, я не знаю о VB), ДЛЯ циклов были реализованы по-другому.

, Например, циклично выполняться десять раз

ДЛЯ N=1 К 10

...

NEXT N

----ИЛИ----для нахождения суммы четных чисел ниже 100

ДЛЯ N=0 К 100 шагам 2

...

NEXT N

В C у Вас может быть любое условие в "для" проверить на выход из цикла. Более гибкий, я думаю.

0
ответ дан RuntimeException 30 April 2012 в 04:11
поделиться
  • 1
    Это было намерением;-). Хотя я can' t думают другой или больше устойчивых подходов прямо сейчас, чем любая замена кавычки и разделяют впоследствии (icabod' s решение), или разделенный вокруг кавычек и удаляют их – Joey 23 September 2011 в 10:42

самая 'практичность' означает, что потенциальный главный CS должен изучить ошибки Kernighan в разработке C, особенно печально известное то, которое для цикла оценивает для условия неоднократно, которое копирует, в то время как и не удается соответствовать поведению большинства других языков, которые реализуют для цикла.

Muaahahahaa!

мне нравится основное (игра слов intented) утверждения рецензента:

  • ошибки Kernighan
  • печально известный факт
  • сбои для соответствия поведению большинства других языков

Для меня это пахнет кем-то, кто никогда не следовал за освоением C основной features/philosphy.

Введение

, Поскольку я все еще изучал физику в университете, я нашел, что C (т.е. подобный языкам C) должны были стать моим предпочтительным языком, когда я обнаружил C для [1 134] цикл.

Так, по-видимому, отказ стиля является чьим-либо успехом стиля. Это закончит субъективную часть этого обсуждения.

, Возможно, Kernigan для нужно было назвать циклом?

Просто ребячество? Возможно, нет.

автор обзора, по-видимому, решил, что каждая конструкция языка должна иметь то же поведение через языки. Так переименовывая для [1 135] как [1 136] цикл упростил бы его дискомфорт.

проблема состоит в том, что автору не удается понять, что C для [1 137] является расширением [1 138] в то время как , не различный цикл. Это означает , в то время как синтаксическая сахарная облегченная версия [1 140] для [1 140], вместо , в то время как другие языки, где для [1 142], возможно, кастрировался вниз.

C для действительно необходимого?

Заключение в кавычки автора обзора, он делает следующие утверждения [приблизительно 1 143] для [1 143] и в то время как :

  • для [1 145] для постоянных циклов, с начала к концу
  • , в то время как для циклов, оценивая условие при каждом повторении

, Имеющими ортогональными функциями является хорошая вещь, когда можно объединить их. Но на всех языках я знаю, нет никакого способа объединиться и для [1 147] и в то время как вместе.

Пример: Что, если для языка рецензента Вам нужен цикл, идущий с начала в конец (как для [1 149]), но все еще способный оценить при каждом повторении цикла (как в то время как ): Вы могли должны быть найти в подмножестве контейнера (не целый контейнер), значение согласно некоторому тесту с сохранением информации?

В подобном языку C, Вы используете для [1 151]. На идеальном языке рецензента Вы просто, ну, в общем, взламываете некоторый ужасный код, крича, потому что Вы не имеете цикл for_while (или C для [1 153] цикл).

Заключение

я полагаю, что мы можем суммировать критика рецензента C (и подобный языкам C) со следующим утверждением" печально известная ошибка Kernigan не предоставления C синтаксис предыдущих, существующих языков ", который может быть получен в итоге снова, поскольку" Никогда не думают отличающиеся ".

Заключение в кавычки Bjarne Stroustrup:

существует только два вида языков: те, которые люди жалуются на и те, никто не использует.

Так, в целом, комментарий рецензента нужно рассмотреть как похвалу.

^_^

1
ответ дан paercebal 30 April 2012 в 04:11
поделиться
  • 1
    Теперь Вы вынудили меня ответить хорошим решением:-), – jeb 23 September 2011 в 10:40