Java - общие проблемы

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

Я не буду давать указания относительно того, как структурировать ответы или что «слишком легко» считать ошибкой, поскольку именно для этого и проводится голосование.

Смотрите также:

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
50
0
14 543
28

Ответы 28

Пойду первым, вот один, которого я поймал сегодня. Это было связано с путаницей Long / long.

public void foo(Object obj) {
    if (grass.isGreen()) {
        Long id = grass.getId();
        foo(id);
    }
}
private void foo(long id) {
    Lawn lawn = bar.getLawn(id);
    if (lawn == null) {
        throw new IllegalStateException("grass should be associated with a lawn");
    }   
}

Очевидно, имена были изменены, чтобы защитить невиновных :)

Это помогло бы объяснить проблему и ее решение. Я предполагаю, что проблема здесь в том, что сигнатура метода foo () ожидает примитив. Код вообще компилируется?

Jon Coombs 20.06.2014 04:20

если у вас есть метод с тем же именем, что и конструктор, НО имеет возвращаемый тип. Хотя этот метод выглядит как конструктор (для новичка), это НЕ.

передача аргументов в основной метод - нубам нужно время, чтобы привыкнуть.

прохождение. в качестве аргумента пути к классам для выполнения программы в текущем каталоге.

Понимая, что имя массива строк неочевидно

hashCode и равно: многие java-разработчики с опытом работы более 5 лет не совсем понимают это.

Установить против списка

До JDK 6 в Java не было NavigableSets, чтобы можно было легко перебирать Set и Map.

> До JDK 6 в Java не было NavigableSets, чтобы можно было легко выполнять итерацию по Set и Map. Обычные наборы в Java легко повторяются. NavigableSets просто добавляют такие операции, как «найти первый элемент, меньший или равный X». Полезно, но не обязательно просто повторять.

DrPizza 04.10.2008 14:19

SortedSet (начиная с Java 1.3) имеет методы headSet и tailSet, которые обеспечивают большую часть этих функций.

finnw 04.10.2008 16:10

Попробуйте прочитать Пазлы Java, который полон страшных вещей, даже если вы не сталкиваетесь с ними каждый день. Но это сильно подорвет ваше доверие к языку.

Это в моем списке дел, которые нужно прочитать.

Alan 04.10.2008 10:03

Это отличная книга, но большинство «ошибок» в головоломках - это вещи, которые на практике просто не бывает. Это чрезвычайно эзотерические крайние случаи, из-за которых я сказал: «Кто бы мог написать это в любом случае!»

oxbow_lakes 04.10.2008 15:45

Большинство ошибок связано с отчетами об ошибках, поэтому очевидно, что люди действительно сталкиваются с этими вещами, а затем очень запутываются. (Я написал последнюю программу в книге (кроме названия), но намеренно.)

Tom Hawtin - tackline 04.10.2008 17:31

Не воспринимайте головоломки Java как удар по Java. Большинство вещей там больше похоже на «Java далеко не идеальна», чем «Java сломана». Другие языки могут доставить вам гораздо больше проблем, вызывающих путаницу.

TREE 16.10.2009 23:55

Перефразируя разговор с Джошем Блошем из «Кодеры за работой». JB: Почему нет книги под названием «C Puzzlers»? Автор: Потому что это все загадки. ДБ: Да, у каждого языка есть крайние случаи. Это заслуга Java, что их можно перечислить в одной небольшой книге.

Chip McCormick 20.01.2013 22:25

Сравнение равенства объектов с использованием == вместо .equals() - что ведет себя совершенно иначе для примитивов.

Эта проблема гарантирует, что новички будут сбиты с толку, когда "foo" == "foo", но new String("foo") != new String("foo").

Интересно, что Groovy использует '==' для сравнения значений, а не для сравнения идентичности объектов. Будьте осторожны при копировании!

Michael Easter 05.10.2008 02:29

Чтобы следовать из этого ... String j = "foo"; System.out.println (j == "foo"); // Выводит истину

blitzen 26.11.2014 02:30

Практическое правило: если переменная имеет метод equals(), используйте его.

noamtm 10.07.2016 12:54

Переопределение equals (), но не hashCode ()

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

Я сделал что-то глупое с хэш-картами в эти дни, я использовал хеш чего-то в качестве ключа для карты, а не сам объект. При моем первом столкновении с хешем у меня возникли проблемы, поскольку метод equals для целого числа возвращал бы true, даже если метод equals для объекта возвращал бы false.

Ravi Wallau 02.08.2009 23:42

Глупо было изобретать колесо (и, возможно, преждевременно оптимизировать); java.util.HashMap эффективно использует хэш объекта в качестве ключа (для повышения эффективности), но правильно обрабатывает коллизии, используя корзины. Всегда сначала ищите существующий класс, который имеет желаемую функциональность!

Andrzej Doyle 09.09.2009 18:49

Не говоря уже о замене equals неправильной подписью. public boolean equals(MyStuff other) ... вместо public boolean equals(Object other) ...

Dirk 18.01.2011 15:45

Я думаю, что очень хитрым является метод String.substring. Это повторно использует тот же базовый массив char[], что и исходная строка, с другими offset и length.

Это может привести к очень трудно заметным проблемам с памятью. Например, вы можете анализировать очень большие файлы (возможно, XML) на несколько небольших битов. Если вы преобразовали весь файл в String (вместо того, чтобы использовать Reader для «обхода» файла) и использовали substring для захвата нужных вам битов, вы все равно несете за кулисами полный массив char[] размером с файл. Я видел, как это происходило несколько раз, и заметить это бывает очень сложно.

Фактически, это прекрасный пример того, почему интерфейс нельзя полностью отделить от выполнение. И это было прекрасным введением (для меня) несколько лет назад, почему вы должны с подозрением относиться к качеству стороннего кода.

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

Stephen Denne 04.10.2008 15:06

Исходный код библиотеки классов Java всегда интересно читать, как к лучшему, так и к худшему. ;)

Chris Mazzola 04.10.2008 17:52

Можно представить себе оптимизацию виртуальной машины, при которой такой массив может быть частично собран в сборку мусора, если будет доказано, что части недоступны.

John Nilsson 27.03.2010 21:39

Обратите внимание, что этот ответ теперь частично устарел. В более новой версии JDK подстрока не действует. Соответствующий ответ.

Denys Séguret 10.01.2013 19:43

Чтобы сделать этот список полным, какая версия JDK меняет поведение?

bohdan_trotsenko 23.07.2013 14:41

Изменение было в JDK 7u6, помеченном как ошибка нет. 4513622.

FilipK 02.12.2013 13:43

Еще один момент, на который я хотел бы обратить внимание, - это (слишком распространенное) стремление сделать API универсальными. Использование хорошо продуманного универсального кода - это нормально. Создать свой собственный сложно. Очень сложный!

Достаточно взглянуть на функции сортировки / фильтрации в новом Swing JTable. Это полный кошмар. Очевидно, что вы, вероятно, захотите объединить фильтры в цепочку в реальной жизни, но я обнаружил, что это невозможно сделать без использования только необработанной типизированной версии предоставленных классов.

Не очень специфично для Java

Christophe Roussy 13.06.2017 11:25

Манипулирование компонентами Swing извне потока отправки событий может привести к ошибкам, которые чрезвычайно трудно найти. Это то, о чем часто забываем даже мы (как опытные программисты с 3-мя годами опыта в Java)! Иногда эти ошибки проникают внутрь после правильного написания кода и небрежного рефакторинга впоследствии ...

Смотрите этот руководство, почему вы должен.

Хэш по умолчанию не является детерминированным, поэтому, если он используется для объектов в HashMap, порядок записей на этой карте может меняться от запуска к запуску.

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

public static void main(String[] args) {
    System.out.println(new Object().hashCode());
}

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

Это не ошибка, это ожидаемое поведение для хэш-карты. и есть класс карты (LinkedHashMap), основная цель которого - сохранить порядок итераций.

finnw 27.03.2010 21:10

@finnw, для меня это была ошибка, когда я пытался выяснить, что сделала моя программа, и в следующий раз, когда я запустил ее с тем же входом, она выдала другой результат. В конце концов я обнаружил, что Object.hashCode() может давать разные значения даже для первого созданного мной объекта. LinkedHashMap полезен, но в моем случае мне не нужно было сохранять порядок вставки или доступа, и я пытался максимально эффективно использовать память, поэтому, хотя Object.hashCode() подходил для моего алгоритма, я переборщил с ним, чтобы просто получить детерминизм.

Stephen Denne 28.03.2010 04:50

Даже в C# не гарантируется стабильность самого хэш-кода. Хеш-коды для одинаковых строк могут различаться в разных версиях .NET Framework и на разных платформах (например, 32-разрядных и 64-разрядных) для одной версии. NET Framework. В некоторых случаях они могут даже различаться в зависимости от домена приложения ». В результате хэш-коды никогда не должны использоваться за пределами домена приложения, в котором они были созданы, они никогда не должны использоваться в качестве ключевых полей в коллекции и они никогда не должны сохраняться ». msdn.microsoft.com/en-us/library/system.string.gethashcode.a‌ spx Похоже на Java, тем более.

Jon Coombs 20.06.2014 03:53

Это просто потому, что hashCode объекта является его адресом памяти (или функцией этого адреса). Это согласуется с методом класса Object equals (), который также сравнивает адреса памяти. Любая разумная реализация hashCode для подкласса не будет зависеть от расположения в памяти, а должна зависеть от содержимого объекта.

nimrodm 19.04.2020 13:04

SimpleDateFormat не является потокобезопасным.

(un) Бокс и долгая / долгая путаница. В отличие от опыта до Java 5, вы можете получить исключение NullPointerException во второй строке ниже.

Long msec = getSleepMsec();
Thread.sleep(msec);

Если getSleepTime () возвращает значение null, при распаковке выполняется ошибка.

Или вы можете использовать long вместо Long, и вы получите NPE на одну строчку раньше.

MatrixFrog 15.10.2011 10:05

List<Integer> list = new java.util.ArrayList<Integer>();
list.add(1);
list.remove(1); // throws...

Старые API-интерфейсы не разрабатывались с учетом бокса, поэтому перегружайте их примитивами и объектами.

Среди распространенных ошибок, хорошо известных, но все же иногда кусающих программистов, есть классический if (a = b), который встречается во всех C-подобных языках.

В Java это может работать, конечно, только если a и b логические. Но я слишком часто вижу, как новички тестируют if (a == true) (тогда как if (a) короче, читаемее и безопаснее ...) и иногда по ошибке пишут if (a = true), задаваясь вопросом, почему тест не работает. Для тех, кто этого не понимает: последний оператор сначала присваивает truea, а затем выполняет тест, который всегда успешен!

-

Тот, который кусает многих новичков и даже некоторых отвлекающих более опытных программистов (нашел это в нашем коде), if (str == "foo"). Обратите внимание, что мне всегда было интересно, почему Sun отменяет знак + для строк, но не знак ==, по крайней мере, для простых случаев (с учетом регистра).

Для новичков: == сравнивает ссылки, а не содержимое строк. У вас может быть две строки с одинаковым содержимым, хранящиеся в разных объектах (разные ссылки), поэтому == будет ложным.

Простой пример:

final String F = "Foo";
String a = F;
String b = F;
assert a == b; // Works! They refer to the same object
String c = "F" + F.substring(1); // Still "Foo"
assert c.equals(a); // Works
assert c == a; // Fails

-

Еще я видел if (a == b & c == d) или что-то в этом роде. Это работает (как ни странно), но мы потеряли ярлык логического оператора (не пытайтесь писать: if (r != null & r.isSomething())!).

Для новичков: при оценке a && b Java не оценивает b, если a ложно. В a & b Java оценивает обе части, а затем выполняет операцию; но вторая часть может провалиться.

[EDIT] Хорошее предложение от J Coombs, я обновил свой ответ.

if (a = b) вызывает ошибку времени компиляции, если a не имеет типа boolean или Boolean. Ура за строгий набор текста. Бу за плохой синтаксис.

Tom Hawtin - tackline 09.10.2008 22:34

PhiLho, похоже, вы предположили, что читатель уже знает Java и знает, что вы имеете в виду. Это помогло бы немного подробнее объяснить, что здесь не так, а что правильно. (Например, успешное присвоение или сравнение; & vs. &&.)

Jon Coombs 20.06.2014 04:07

Примечание. Что касается (str == "foo"), проблема заключается в том, что оператор ==, в отличие от C#, не перегружен для строк, поэтому == только сравнивает идентификаторы объектов, а не сравнивает строки.

Jon Coombs 20.06.2014 04:24

@JCoombs Спасибо, что указали на это, я обновил свой ответ. Обратите внимание, что новые языки программирования, такие как Scala, Dart или Ceylon, делают правильные вещи для == (вызывая .equals за сценой).

PhiLho 11.07.2014 15:52

Есть два, которые меня немного раздражают.

Дата / Календарь

Во-первых, классы Java Date и Calendar серьезно испорчены. Я знаю, что есть предложения по их устранению, я просто надеюсь, что они удастся.

Calendar.get (Calendar.DAY_OF_MONTH) основан на 1
Calendar.get (Calendar.MONTH) - 0 на основе

Автобокс мешает думать

Другой - Integer vs int (это касается любой примитивной версии объекта). Это, в частности, раздражение, вызванное тем, что вы не думаете, что Integer отличается от int (поскольку вы можете обрабатывать их одинаково большую часть времени из-за автобокса).

int x = 5;
int y = 5;
Integer z = new Integer(5);
Integer t = new Integer(5);

System.out.println(5 == x);     // Prints true
System.out.println(x == y);     // Prints true
System.out.println(x == z);     // Prints true (auto-boxing can be so nice)
System.out.println(5 == z);     // Prints true
System.out.println(z == t);     // Prints SOMETHING

Поскольку z и t являются объектами, даже несмотря на то, что они имеют одинаковое значение, они (скорее всего) являются разными объектами. На самом деле вы имели в виду:

System.out.println(z.equals(t));   // Prints true

Это может быть проблемой для отслеживания. Вы что-то отлаживаете, все выглядит нормально, и вы, наконец, обнаруживаете, что ваша проблема в том, что 5! = 5, когда оба являются объектами.

Возможность сказать

List<Integer> stuff = new ArrayList<Integer>();

stuff.add(5);

так приятно. Это сделало Java настолько удобнее в использовании, что не нужно было помещать все эти строки «new Integer (5)» и «((Integer) list.get (3)). IntValue ()» повсюду. Но эти преимущества приходят с этим.

Мне потребовалось два 8-часовых дня, чтобы понять, почему все наши свидания были на месяц перерыв ... Я выдергивал волосы!

Knobloch 05.10.2008 16:25

Месяц на основе 0 - это вещь POSIX (и библиотеки C). То, что это стандарт, не означает, что ему всегда нужно следовать.

Tom Hawtin - tackline 09.10.2008 22:35

z == t всегда ложно. Два отдельно новых объекта имеют разную идентичность. С другой стороны, если вы укажете Integer.valueOf (5) в обоих случаях, то это будет один и тот же объект: значения от -128 до 127 должны быть кэшированными значениями.

Chris Jester-Young 06.05.2009 15:40

Если x == z или 5 == z истинно, это из-за auto-распаковка на z, а не из-за какого-либо автоматического бокса. Integer.valueOf (5)! = New Integer (5) (вспоминая мой предыдущий комментарий о новом объекте, имеющем отличную идентичность от любого другого отдельно созданного объекта).

Chris Jester-Young 06.05.2009 15:41

-1. Вы ошибаетесь насчет примера z == t, как описывает @Chris Jester-Young. Возможно, вы путаете это с аналогичным примером в .NET, где z == tможет истинно.

finnw 15.07.2010 13:03

этот несколько раз превзошел меня, и я слышал, что довольно много опытных Java-разработчиков тратят впустую много времени.

ClassNotFoundException --- вы знаете, что класс находится в пути к классам, НО вы НЕ уверены, почему класс НЕ загружается.

Собственно, у этого класса есть статический блок. Произошло исключение в статическом блоке, и кто-то съел исключение. они НЕ ДОЛЖНЫ. Они должны бросать ExceptionInInitializerError. Так что всегда ищите статические блоки, которые могут вас сбить с толку. Это также помогает переместить любой код в статических блоках в статические методы, чтобы упростить отладку метода с помощью отладчика.

Один раз меня достал, но мне потребовались минуты, чтобы разобраться в кодовой базе из сотен тысяч строк - я не знаю, как опытный Java-разработчик был озадачен этим.

searchengine27 06.05.2015 18:47

Целочисленное деление

1/2 == 0 not 0.5

... наряду с общими правилами преобразования / продвижения / вывода типов с помощью чисел. Например. 1/2.0 действительно имеет значение 0,5, как и 1d/2, и я уверен, что некоторые из головоломок Java связаны именно с тем, когда происходит продвижение, и, следовательно, происходит ли переполнение или нет.

Andrzej Doyle 09.09.2009 18:51

не специфично для java, хотя

cmcginty 05.09.2012 04:41

Поплавки

Я не знаю, много раз я видел

floata == floatb

где должен быть "правильный" тест

Math.abs(floata - floatb) < 0.001

Я действительно хочу, чтобы BigDecimal с буквальным синтаксисом был десятичным типом по умолчанию ...

Это не относится к Java, но касается способа представления чисел с плавающей точкой. По крайней мере, у C, C++, Python и Perl есть эти проблемы, и, вероятно, у многих других они есть.

rbrito 19.08.2012 02:38

Просто потому, что все спрыгнули со скалы ...

John Nilsson 23.10.2012 23:35

"правильный" не совсем подходит для всех случаев (но в этом суть). В противном случае я полагаю, что Java предоставила бы для этого универсальное решение. Я имею в виду, что ваше решение не будет работать для 1.001E-15 по сравнению с 1.002E-15.

PhiLho 11.07.2014 15:35

Использовать BigDecimal вместо float или даже double - ужасная идея. Использование BigDecimal сильно снижает производительность, и его следует использовать только тогда, когда вам нужна точность. float и double намного лучше, чем BigDecimal, если вы не создаете службу, которая обрабатывает деньги.

searchengine27 06.05.2015 18:45

Я не верю, что вы могли бы поддержать «огромный», если бы вы провели некоторое исследование реальных, типичных Java-систем. В приложениях, где все накладные расходы на вычисления «огромны», вы не стали бы использовать java для начала, и даже если бы вы это сделали, вы всегда могли бы иметь вместо этого специальные, нестандартные типы для критических расчетов с потерей производительности. Кроме того, я уверен, что можно многое сделать, чтобы разница в производительности не была столь значительной даже для приложений, критичных к производительности. Лучшие реализации плюс аппаратное ускорение могут творить чудеса.

John Nilsson 07.05.2015 01:31

Подобные ситуации news.ycombinator.com/item?id=9476139 просто невозможны без реальных усилий и злого умысла.

John Nilsson 07.05.2015 01:32

ИМХО 1. Использование vector.add (Collection) вместо vector.addall (Collection). Первый добавляет объект коллекции в вектор, а второй добавляет содержимое коллекции. 2. Использование синтаксических анализаторов xml, которые поступают из нескольких источников, таких как xerces, jdom, не имеет прямого отношения к программированию. Полагаться на разные парсеры и иметь их jar-файлы в пути к классам - это кошмар.

Это должна быть старая проблема. Вектор фактически больше не используется. А с общими списками это невозможно.

John Nilsson 05.10.2008 18:44

@John, Vector также является общим

finnw 27.03.2010 21:07

Неизменяемые строки, что означает, что некоторые методы не изменяют исходный объект, а вместо этого возвращают измененную копию объекта. Начиная с Java, я все время забывал об этом и задавался вопросом, почему метод replace не работает с моим строковым объектом.

String text = "foobar";
text.replace("foo", "super");
System.out.print(text); // still prints "foobar" instead of "superbar"

Примечание: строки неизменяемы и в Python, и в C#. Но я согласен с тем, что всякий раз, когда вы впервые сталкиваетесь с этим, эта концепция может сбивать с толку, если у вас есть опыт работы с изменяемыми строками и, следовательно, вы склонны рассматривать их в основном как массивы символов. Также обратите внимание, что по этой причине такие важные вещи, как пароли, следует обрабатывать с помощью char [], поскольку нет возможности стереть строку. stackoverflow.com/questions/8881291/…

Jon Coombs 20.06.2014 04:02

Ваш пример довольно тривиален, хотя да, он поставит вас в тупик. Я бы сказал, что более важная вещь, которую я на самом деле видел (а это не должны быть опытные разработчики), связанная с этим, - это синхронизация с неизменяемым неокончательным объектом: <code> class Foo {Long bar = new Long (0L); public void baz () {синхронизировано (бар) {бар + = 1L; }}} </code> В этом примере два конкурирующих потока никогда не будут блокироваться на одном и том же объекте, и 'bar', скорее всего, никогда не будет тем, чем вы хотите (при условии, что два потока не имеют допустимой синхронизации до куча).

searchengine27 06.05.2015 18:55

@Jon Coombs Фактически, вы можете стереть строку. Вы можете использовать Reflection или Unsafe. Это позволяет делать некоторые сумасшедшие вещи, например, изменять строковый литерал так, чтобы попытка распечатать литерал «foo» фактически выводила «bar» (из-за пула строк)

Kaiser Keister 01.10.2019 05:00

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

Реализация системы универсальных типов со стиранием типов ужасна и сбивает с толку большинство студентов, когда они впервые узнают о универсальных типах в Java: почему нам все еще нужно приводить типы, если параметр типа уже предоставлен? Да, они обеспечивали обратную совместимость, но довольно глупой ценой.

Я только что наткнулся на этот:

double[] aList = new double[400];

List l = Arrays.asList(aList);
//do intense stuff with l

Кто-нибудь видит проблему?


Что происходит, Arrays.asList() ожидает массив типов объектов (например, Double []). Было бы неплохо, если бы он просто выдавал ошибку для предыдущего ocde. Однако asList() также может принимать такие аргументы:

Arrays.asList(1, 9, 4, 4, 20);

Итак, код создает List с одним элементом - double[].

Я должен был догадаться, когда для сортировки массива из 750000 элементов потребовалось 0 мс ...

Doubles.asList от Guava (guava-libraries.googlecode.com/svn/trunk/javadoc/com/google‌ /…) делает то, что вы хотите. Аналогично Ints.asList делает то же самое для int[] и т. д.

finnw 15.07.2010 14:02

Вы также можете делать что-то, не проходя лизис: double [] sorted = aList.clone (); Arrays.sort (отсортировано); ... а Боб твой дядя. Вы также можете транслировать его и делать то же самое, если хотите. В java.util.Arrays есть много хороших вещей, это не просто asList.

Haakon Løtveit 19.03.2018 11:41

"a,b,c,d,,,".split(",").length

возвращает 4, нет 7, как вы могли (и я, конечно, сделал) ожидать. split игнорирует все завершающие возвращенные пустые строки. Это значит:

",,,a,b,c,d".split(",").length

возвращает 7! Чтобы добиться того, что я бы назвал «наименее удивительным», вам нужно сделать что-нибудь весьма удивительное:

"a,b,c,d,,,".split(",",-1).length

чтобы получить 7.

также обратите внимание, что split принимает регулярное выражение, поэтому для разделения на точку вам нужно будет сделать "a.b".split("\.")

Christophe Roussy 13.06.2017 11:21

Я думаю, что у меня большая проблема, которая всегда ставила меня в тупик, когда я был молодым программистом, был исключение одновременной модификации при удалении из массива, который вы повторяли:

  List list = new ArrayList();
    Iterator it = list.iterator();
    while(it.hasNext()){
      //some code that does some stuff
      list.remove(0); //BOOM!
  }

Не совсем специфично для Java, поскольку многие (но не все) языки реализуют это таким образом, но оператор % не является истинным оператором по модулю, поскольку он работает с отрицательными числами. Это делает его оператором остаток и может привести к некоторым сюрпризам, если вы об этом не знаете.

Следующий код может выводить либо «четное», либо «нечетное», но это не так.

public static void main(String[] args)
{
    String a = null;
    int n = "number".hashCode();

    switch( n % 2 ) {
        case 0:
            a = "even";
            break;
        case 1:
            a = "odd";
            break;
    }

    System.out.println( a );
}

Проблема в том, что хэш-код для «числа» отрицательный, поэтому операция n % 2 в коммутаторе также отрицательна. Поскольку в переключателе нет случая, чтобы иметь дело с отрицательным результатом, переменная a никогда не устанавливается. Программа распечатает null.

Убедитесь, что вы знаете, как оператор % работает с отрицательными числами, независимо от того, на каком языке вы работаете.

Разве вы не должны сделать ((n% 2) == 0) означает даже еще ложное?

user55776 25.11.2009 04:59

+1 за »Убедитесь, что вы знаете, как оператор% работает с отрицательными числами, независимо от того, на каком языке вы работаете.« - Тем более, что почти каждый язык обрабатывает модуль по-разному.

Joey 17.05.2011 22:30

Когда вы создаете duplicate или slice из ByteBuffer, он не наследует значение свойства order из родительского буфера, поэтому такой код не будет делать то, что вы ожидаете:

ByteBuffer buffer1 = ByteBuffer.allocate(8);
buffer1.order(ByteOrder.LITTLE_ENDIAN);
buffer1.putInt(2, 1234);

ByteBuffer buffer2 = buffer1.duplicate();
System.out.println(buffer2.getInt(2));
// Output is "-771489792", not "1234" as expected

Более того, они используют общий буфер. duplicate () предназначен для создания другого класса для записи, а не для создания клона и забвения его происхождения.

bohdan_trotsenko 23.07.2013 14:52

    System.out.println(Calendar.getInstance(TimeZone.getTimeZone("Asia/Hong_Kong")).getTime());
    System.out.println(Calendar.getInstance(TimeZone.getTimeZone("America/Jamaica")).getTime());

Выход такой же.

Было бы неплохо включить объяснение. Вот моя попытка: в обоих случаях текущее время в любом месте разрешается в одно и то же время в абсолютном выражении, а то, что печатается, фактически основано на вашем собственном часовом поясе (например, UTC / GMT, если вы находитесь в Англии).

Jon Coombs 20.06.2014 03:45

Использование подстановочного знака универсальных шаблонов ?.

Люди видят это и думают, что должны, например используйте List<?>, когда им нужен List, к которому они могут добавить что угодно, не думая, что List<Object> уже делает это. Затем они задаются вопросом, почему компилятор не позволяет им использовать add(), потому что List<?> на самом деле означает «список какого-то определенного типа, которого я не знаю», поэтому единственное, что вы можете сделать с этим List, - это получить из него экземпляры Object.

Однажды мне было интересно отладить TreeSet, так как я не знал об этой информации из API:

Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface. http://download.oracle.com/javase/1.4.2/docs/api/java/util/TreeSet.html

Объекты с правильными реализациями equals / hashcode добавлялись и никогда больше не встречались, поскольку реализация compareTo несовместима с equals.

Другие вопросы по теме