divideUnsignedLong — совершенно точно не ошибка. Это низкоуровневый метод, реализующий деление переменных типа long, интерпретированных как беззнаковые. Если в этот метод передадут divisor = 0, то упасть с "ArithmeticException: / by zero" — самое логичное поведение, этот случай не надо рассматривать специально, добавляя лишние ветки в низкоуровневый код.
Я не знаю точно, по каким критериям отбирают. Знаю, что некоторые компании пытаются заслать больше участников, но их ограничивают. Нас пока не выгоняли :-)
Думаю, если вы покупаете авиабилеты зарубежной авиакомпании или бронируете отель за рубежом, практически наверняка имя, дата рождения и номер паспорта осядут в каких-нибудь зарубежных базах данных.
Во-первых, стажёров на летнюю практику набирает не JetBrains, а JetBrains Research. Это отдельная организация (хоть и финансируемая JetBrains) со своей структурой. HR-отдел JetBrains совершенно не занимается стажировками. Во-вторых, стажёров набирают конкретные менторы. То есть любой штатный сотрудник JetBrains имеет право объявить задачу на стажировку и объявить свой собственный способ отбора студента или студентов на эту задачу. Там есть некоторые ограничения (например, сперва идёт тестовое задание, а потом собеседование), но в целом этот один человек всё решает: и как формулировать задание, и по каким критериям его проверять, и кого звать на собеседование, и кого в итоге пригласить на стажировку. Студент, желающий проходить стажировку, подаётся именно на конкретный проект. Может податься на 2-3 проекта, но на каждом будет своё тестовое задание и свой ментор. Важно то что в итоге на каждом проекте место обычно одно, больше — редко.
К примеру, в прошлом году я брал стажёра. Я дал одну задачу, указав, что решение обязательно должно быть на Java. Мне прислали 16 решений, шестерых я пригласил на собеседование и одного в итоге взял. Я не уверен, высылал ли я каждому из десяти не прошедших на собеседование мотивированный отказ, хотя у меня есть заметки по каждому решению. Но если бы меня спросили, я бы, конечно, объяснил недостатки решения. Пятерым не прошедшим собеседование я тоже никак не мотивировал отказ. В принципе как тут мотивируешь? Они все молодцы, неплохо справились с тестовым заданием, показали довольно приличный для студента уровень знаний, но нашёлся среди них человек, который показал более высокий уровень знаний и опыт. Это же не экзамен, а соревнование, позиция всего одна.
Я бы поостерёгся разрешать писать на любом языке из top-50. Когда присылают 16 решений, их будет очень сложно сравнить. Если язык мне совсем незнаком, мне придётся разбираться, как это скомпилировать и запустить. Если я не смогу в итоге запустить, это я корявый, не ту версию компилятора поставил, или это решение корявое? Могу ли я оценить качество кода на незнакомом мне языке? Если в итоге мой проект на Java, а человек демонстрирует уверенное знание PHP, как я пойму, насколько он хорошо будет писать на Java? Мне кажется, что ограничить язык (а лучше и версию) разумно. Но тут каждому ментору виднее, конечно.
Почему вы отождествляете пакет и неймспейс? Я вот утверждаю, что класс ближе к понятию неймспейс, чем пакет, потому что как и в C++ в классе могут содержаться функции (статические методы), константы (статические поля) и классы (статические вложенные). А в пакете могут быть только классы. Например, в C++ есть std::sprintf, который можно не квалифицировать, если написать using. В Java есть похожий метод java.lang.String::format. Его тоже можно не квалифицировать, используя import static. Но так мало кто делает, все используют квалификатор (пусть и неполный) String.format.
Интересно, часто вы видели в джаве out.println вместо System.out.println со статическим импортом System.out? Ближайший аналог неймспейсов в джаве — это именно статические импорты.
Отрабатывает или не отрабатывает — это вопрос вторичный. Весь опыт использования статических анализаторов говорит, что пути обработки ошибок тестируют заметно меньше, чем корректные пути работы программы. Для реальных багов, выявленных в коде обработки ошибок статическими анализаторами всегда существенно выше.
Довели бы уж тогда до конца. Если умножение матриц этих расписать по определению, там видно, что некоторые действия лишние, и можно вывести более эффективную формулу без матриц.
Это вы, похоже, издеваетесь. Давайте в пустом проекте подчеркнём и напишем «в этом проекте в будущем возможны ошибки». Любой код можно испортить так, чтобы там была ошибка в будущем.
У нас можно аннотировать контракты через действие Edit method contract, и они сохраняются в специальные XML-ки. Их можно как коммитить в VCS, так и деплоить в бинарный репозиторий и подкачивать вместе с библиотекой. Вот тут можно почитать про внешние аннотации, а вот тут конкретно про контракты.
К сожалению, такой контракт как у isNotEmpty целиком не опишешь внешней аннотацией, можно только null -> false написать, но полностью поведение метода не специфицируешь. Такие методы мы можем захардкодить при необходимости (внутренний язык контрактов богаче, чем опубликованный для всех). Есть предложение расширить общий язык контрактов, чтобы можно было писать (param1 != null && param1.length() > 0) -> true; () -> false, но никаких обещаний, будет ли это сделано, когда и в какой форме.
Интересно, кстати, это вы вручную преаннотировали org.apache.commons.lang3.StringUtils.isNotEmpty? Вряд ли у вас такой крутой межпроцедурный анализ :-)
Да, вам работать и работать ещё над джавой, даже в статье хватает ложных предупреждений, а вы ведь явно отбирали что поместить в статью.
StringBuilder orderBy = new StringBuilder();
....
if (orderBy.length() > 0) {
orderBy.delete(orderBy.length() - 2, orderBy.length());
orderBy.insert(0, " order by ");
}
Сразу же видна разница в экспертизе :-) Я себе мгновенно представил, что в опущенном коде происходит: там в цикле что-то дописывается в StringBuilder, и в конец приписывается ", ". И так и оказалось! В этом StringBuilder никогда не может быть одного символа. Либо ноль (если в цикл ни разу не зашли), либо не меньше двух (потому что как минимум одна запятая с пробелом). Вы можете сколько угодно говорить, что код выглядит опасно, ненадёжно и т. д., но это чистый false-positive.
@Override
public boolean handle(ErrorEvent event, App app) {
Throwable t = event.getThrowable();
..
return true;
Хвастаетесь же, что у вас по десять исключений в каждой инспекции :-) Этот метод реализует метод интерфейса. В этом случае он действует в соответствии с документацией интерфейса: всегда возвращает true, сигнализируя о том, что исключение всегда обработано. В данном случае это не ошибка. Не стоит выдавать это предупреждение для реализаций интерфейсов.
public <T> T getSingleResultFromCache(QueryKey queryKey, List<View> views) {
....
for (Object id : queryResult.getResult()) {
return (T) em.find(metaClass.getJavaClass(), id, views.toArray(....));
}
....
}
Для циклов for-each это может быть спорный, но вполне используемый паттерн в джаве. Аналогичный код без цикла будет:
Iterator<?> it = queryResult.getResult().iterator();
if (it.hasNext()) {
Object id = it.next();
return (T) em.find(metaClass.getJavaClass(), id, views.toArray(....));
}
Итог: две дополнительных строчки и дополнительная переменная в скоупе. И ради чего? Мы по умолчанию в данном случае предупреждение не выдаём (хотя опция есть выдавать), потому что тех, кто так пишет, можно понять. Во всех остальных типах циклов кроме for-each предупреждение выдаётся.
Анализатор обнаружил ситуацию, когда сравнение классов осуществляется по имени. Такое сравнение является некорректным, т.к., согласно спецификации, JVM классы имеют уникальное имя только внутри пакета. Это может стать причиной некорректного сравнения и выполнения не того кода, который планировался.
Это бла-бла совершенно не относится к данному случаю. Это совершенно нормальная ситуация: там сравнение с каким-то названием свойства. Именно с названием, которое может из какого-нибудь XML приходит или ещё откуда-то. Как в данной ситуации сравнить с конкретным классом, загруженным конкретным загрузчиком классов? Сериализовать класс-лоадер в XML? Ну-ну. В бизнес-логике это вполне частый случай, использовать простое имя класса в качестве имени какого-то свойства. Возможно, есть отдельный тест, который убеждается, что в системе нет двух классов с одинаковым именем, объявленных как MetaProperty. В общем, мусорное предупреждение.
Однако есть и весьма вкусные предупреждения. Статью плюсанул. Работайте дальше.
Ценность статического анализа кода, ценность его диагностик не в том, где выдавать ошибку. А в том, где ее НЕ выдавать. На каждую из наших диагностик у нас есть 10, 20, а то и больше исключений, когда срабатывать не надо.
Звучит так будто конкуренты этого не делают. А это, разумеется, не так. И насчёт 10 исключений в каждой диагностике вы, конечно, привираете. Есть простые кейсы, где пара граничных случаев всё описывает.
divideUnsignedLong
— совершенно точно не ошибка. Это низкоуровневый метод, реализующий деление переменных типаlong
, интерпретированных как беззнаковые. Если в этот метод передадутdivisor = 0
, то упасть с "ArithmeticException: / by zero" — самое логичное поведение, этот случай не надо рассматривать специально, добавляя лишние ветки в низкоуровневый код.Ещё не забудьте бинарный сдвиг >>, который должен закрывать вложенный дженерик. В старых плюсах обязательно было пробел ставить в середине.
Оказывается, из ничего тоже можно сделать статью на Хабр!
Уговорили, больше вообще студентов брать не буду. Никто не заставляет, и эгоистом не прослыву.
Во-первых, стажёров на летнюю практику набирает не JetBrains, а JetBrains Research. Это отдельная организация (хоть и финансируемая JetBrains) со своей структурой. HR-отдел JetBrains совершенно не занимается стажировками. Во-вторых, стажёров набирают конкретные менторы. То есть любой штатный сотрудник JetBrains имеет право объявить задачу на стажировку и объявить свой собственный способ отбора студента или студентов на эту задачу. Там есть некоторые ограничения (например, сперва идёт тестовое задание, а потом собеседование), но в целом этот один человек всё решает: и как формулировать задание, и по каким критериям его проверять, и кого звать на собеседование, и кого в итоге пригласить на стажировку. Студент, желающий проходить стажировку, подаётся именно на конкретный проект. Может податься на 2-3 проекта, но на каждом будет своё тестовое задание и свой ментор. Важно то что в итоге на каждом проекте место обычно одно, больше — редко.
К примеру, в прошлом году я брал стажёра. Я дал одну задачу, указав, что решение обязательно должно быть на Java. Мне прислали 16 решений, шестерых я пригласил на собеседование и одного в итоге взял. Я не уверен, высылал ли я каждому из десяти не прошедших на собеседование мотивированный отказ, хотя у меня есть заметки по каждому решению. Но если бы меня спросили, я бы, конечно, объяснил недостатки решения. Пятерым не прошедшим собеседование я тоже никак не мотивировал отказ. В принципе как тут мотивируешь? Они все молодцы, неплохо справились с тестовым заданием, показали довольно приличный для студента уровень знаний, но нашёлся среди них человек, который показал более высокий уровень знаний и опыт. Это же не экзамен, а соревнование, позиция всего одна.
Я бы поостерёгся разрешать писать на любом языке из top-50. Когда присылают 16 решений, их будет очень сложно сравнить. Если язык мне совсем незнаком, мне придётся разбираться, как это скомпилировать и запустить. Если я не смогу в итоге запустить, это я корявый, не ту версию компилятора поставил, или это решение корявое? Могу ли я оценить качество кода на незнакомом мне языке? Если в итоге мой проект на Java, а человек демонстрирует уверенное знание PHP, как я пойму, насколько он хорошо будет писать на Java? Мне кажется, что ограничить язык (а лучше и версию) разумно. Но тут каждому ментору виднее, конечно.
Интересно, часто вы видели в джаве out.println вместо System.out.println со статическим импортом System.out? Ближайший аналог неймспейсов в джаве — это именно статические импорты.
Отрабатывает или не отрабатывает — это вопрос вторичный. Весь опыт использования статических анализаторов говорит, что пути обработки ошибок тестируют заметно меньше, чем корректные пути работы программы. Для реальных багов, выявленных в коде обработки ошибок статическими анализаторами всегда существенно выше.
Довели бы уж тогда до конца. Если умножение матриц этих расписать по определению, там видно, что некоторые действия лишние, и можно вывести более эффективную формулу без матриц.
Интересно, сколько раз на Хабре были числа Фибоначчи на матрицах? Раз пять я, наверно, видел…
У нас можно аннотировать контракты через действие Edit method contract, и они сохраняются в специальные XML-ки. Их можно как коммитить в VCS, так и деплоить в бинарный репозиторий и подкачивать вместе с библиотекой. Вот тут можно почитать про внешние аннотации, а вот тут конкретно про контракты.
К сожалению, такой контракт как у
isNotEmpty
целиком не опишешь внешней аннотацией, можно толькоnull -> false
написать, но полностью поведение метода не специфицируешь. Такие методы мы можем захардкодить при необходимости (внутренний язык контрактов богаче, чем опубликованный для всех). Есть предложение расширить общий язык контрактов, чтобы можно было писать(param1 != null && param1.length() > 0) -> true; () -> false
, но никаких обещаний, будет ли это сделано, когда и в какой форме.Интересно, кстати, это вы вручную преаннотировали
org.apache.commons.lang3.StringUtils.isNotEmpty
? Вряд ли у вас такой крутой межпроцедурный анализ :-)Да, вам работать и работать ещё над джавой, даже в статье хватает ложных предупреждений, а вы ведь явно отбирали что поместить в статью.
Сразу же видна разница в экспертизе :-) Я себе мгновенно представил, что в опущенном коде происходит: там в цикле что-то дописывается в StringBuilder, и в конец приписывается
", "
. И так и оказалось! В этом StringBuilder никогда не может быть одного символа. Либо ноль (если в цикл ни разу не зашли), либо не меньше двух (потому что как минимум одна запятая с пробелом). Вы можете сколько угодно говорить, что код выглядит опасно, ненадёжно и т. д., но это чистый false-positive.Хвастаетесь же, что у вас по десять исключений в каждой инспекции :-) Этот метод реализует метод интерфейса. В этом случае он действует в соответствии с документацией интерфейса: всегда возвращает
true
, сигнализируя о том, что исключение всегда обработано. В данном случае это не ошибка. Не стоит выдавать это предупреждение для реализаций интерфейсов.Для циклов for-each это может быть спорный, но вполне используемый паттерн в джаве. Аналогичный код без цикла будет:
Итог: две дополнительных строчки и дополнительная переменная в скоупе. И ради чего? Мы по умолчанию в данном случае предупреждение не выдаём (хотя опция есть выдавать), потому что тех, кто так пишет, можно понять. Во всех остальных типах циклов кроме for-each предупреждение выдаётся.
Это бла-бла совершенно не относится к данному случаю. Это совершенно нормальная ситуация: там сравнение с каким-то названием свойства. Именно с названием, которое может из какого-нибудь XML приходит или ещё откуда-то. Как в данной ситуации сравнить с конкретным классом, загруженным конкретным загрузчиком классов? Сериализовать класс-лоадер в XML? Ну-ну. В бизнес-логике это вполне частый случай, использовать простое имя класса в качестве имени какого-то свойства. Возможно, есть отдельный тест, который убеждается, что в системе нет двух классов с одинаковым именем, объявленных как MetaProperty. В общем, мусорное предупреждение.
Однако есть и весьма вкусные предупреждения. Статью плюсанул. Работайте дальше.
Звучит так будто конкуренты этого не делают. А это, разумеется, не так. И насчёт 10 исключений в каждой диагностике вы, конечно, привираете. Есть простые кейсы, где пара граничных случаев всё описывает.