Pull to refresh

Comments 42

Спасибо за статью. Раз уж речь про конференции зашла, то у меня такой вопрос: JetBrains Night в этом году будет?

3)


В переменной value действительно может быть null, но в этом случае массив result будет пустым, и мы в цикл никак не зайдём.

А если в массиве лежит 2 действительных значение, а 3-е — null, мы берём последний, передаём в конструктор и ловим НПЕ там?


6) Мне кажется, что в этом примере должна быть ещё проверка на пустую строку, иначе можно IOOBE поймать:


@Test
void name() {
  String nextClassName = new a1().getNextClassName("azaza", "");
}

static class a1 {
  int classCounter;
  public String getNextClassName(String fullName, String shortName) {
    if (shortName == null) {
      return "class_" + classCounter++;
    }

    int index = 0;
    while (Character.isDigit(shortName.charAt(index))) { // <---
      index++;
    }
    if (index == 0 || index == shortName.length()) {
      return "class" + classCounter++;
    }
    return fullName;
  }
}

P. S. Посмотрел статью, на которую ты ссылаешься, там написано


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

Как такое возможно, если в исходниках имя ява-класса не может состоять из цифр?

Спасибо за баг-репорт. Это новая фича in-place refactoring пока не отлажена, в 2020.1 EAP ещё часто падает. В 2019.3 таких проблем нет.

Тогда ошибка будет другой (не Array access) и только в случае, если параметр помечен как @NotNull (либо на основе анализа Идея догадается, что он должен быть не null)

Вы правы )) я сегодня подтормаживаю иногда

Вообще в этом случае мы всё равно по умолчанию ничего не напишем. Мы не предупреждаем обо всех возможных ошибках с nullability, иначе у вас бы был миллион мусорных предупреждений. Мы говорим только о вероятных ошибках. Про элемент массива мы бы сказали, если бы он был объявлен как @Nullable DriverPropertyInfo @Nullable [], то есть элементы были бы тоже аннотированы как Nullable.

Как такое возможно, если в исходниках имя ява-класса не может состоять из цифр?

Ключевая фраза — «по правилам виртуальной машины Java»


JVMS §4.2.1:


Class and interface names that appear in class file structures are always represented in a fully qualified form known as binary names (JLS §13.1). Such names are always represented as CONSTANT_Utf8_info structures (§4.4.7) and thus may be drawn, where not further constrained, from the entire Unicode codespace.

Накодогенерировать можно класс с любым именем.

Любопытно, почему тогда нельзя в исходниках писать чисто цифровые имена классов?

Ты действительно хочешь жить в мире, где возможен подобный код? :-) Опасайтесь своих желаний!

Не хочу, мне интересен механизм возникновения подобных ограничений.

Метод и переменная очевидно не могут называться одними цифрами. Придумывать для типов и для переменных разный набор допустимых символов? Ради чего?

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


Компилятор же соображает, что цифры сразу после ключевого слова class не могут быть переменной вида int и т. п.

Думаю, примерно по той же причине, почему нельзя использовать ключевые слова в качестве имён переменных, полей, методов и классов.

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

Можно, конечно, было изобрести отдельный синтаксис для таких имён, как это сделали в Kotlin:

object `314159265358` {

  @JvmStatic
  fun main(args: Array<String>?) {
    println("Hello, world!")
  }

}


Но зачем нам в Java лишний синтаксический мусор?
Спасибо, что подняли эту тему. Есть фича-реквест иметь возможность скрывать предупреждения в конкретном месте или определённого типа. Например, я могу часто писать так:
if (true && ...) {
   ...
}

или
return;
....

и это совершенно нормальный код на этапе отладки или прототипирования. Собственно, думаю что в режиме отладке или прототипирования у большинства проходит 80% работы и чистый код нужен только в самом конце. IDE же пытается поправлять каждую минуту, в том числе ещё не готовые решения, чем с одной стороны загружает процессор, занимая ресурсы, которые можно было бы потратить на какой-нибудь другой анализ, а с другой — отвлекает от разработки. Конечно в каких то случаях это очень полезные функции, но есть запрос иметь возможность в каких-то случаях их отключать, точечно или по правилам.

P.S.: Кроме того, статистика по отключаемым правилам поможет вам собрать данные на большей выборке, что разработчики считают лишним, а что действительно помогает в работе.

Есть же возможность отключения через особые комментарии

Засорять код для того, чтобы отделаться от IDE в режиме прототипирования? Чтобы внимание рассеивали не только подсветка в нежелательных местах, но и лишний текст? Нет, спасибо, нужно решение в GUI IDE, желательно одним простым чекбоксом, иначе из пушки по воробьям.

Это не на всех инспекция работает, некоторые неотключаемые в принципе. Может с Java плагином не так, но в PHP точно. И ладно если реальная ошибка, а то рабочий код, скопмрованный из мануала, ошибочным объявляет и даже на предупреждение уровень не сменить. Ошибка доступ к приватному свойству извне класса и всё тут. Про биндинг замыкания не слышали.

Да, есть инспекции, а есть аннотаторы, и в некоторых языках почему-то используют аннотаторы, к которым по умолчанию нет механизма саппресса. Почему это так — для меня загадка. В джаве мы всё делаем инспекциями. Но если вы считаете, что у вас что-то подсвечивается неправильно, всегда можно написать баг-репорт или проголосовать за существующих. Про вашу проблему есть репорт?

В джаве return; посреди метода — это не предупреждение, а ошибка компиляции. Если вы совсем не хотите никаких ошибок видеть, а только подсветку синтаксиса, можно отключить гектора в статусной строке:



Только тогда уж оставьте анализ кода при коммите. А то очень часто бывает, что человек думает "ну я же прототипирую, сейчас буду писать коряво, потом исправлю", а в итоге этот корявый код так и живёт десять лет.


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


Кстати, вот вы написали if (true && ...), а ведь это бесполезно. Вы хотели сделать ветку всегда истинной, но в итоге не сделали ничего. Надо было написать if (true || ...). Если вы эту ошибку сделали в редакторе Хабра, вы могли её сделать и в редакторе кода без встроенного статического анализатора. А анализатор подсветит по-разному: в первом случае выделит только true, а во втором — всё условие. Опытный пользователь сразу заметит ошибку, даже если использует подобные условия для прототипирования. В любом случае это полезная визуальная напоминалка, что эта ветка выполнится всегда. Она пригодится при отладке.


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

Кстати, вот вы написали if (true && ...), а ведь это бесполезно.
Это может быть написано для возможности закомментировать разные части условия (или даже всё условие целиком).

Нет, не может быть. Это совсем бесполезно.

Ну почему же бесполезно. Например, условие может выглядеть, как if (condition1 && condition2 && condition3), и нам нужно в процессе разработки включать-выключать разные части этого условия. Мы можем написать это в таком виде:
if (
  true
  && condition1
  && condition2
  && condition3
)
и включать-выключать части условия одним нажатием (однострочными комментариями).

Если же написать это в таком виде:
if (
  condition1
  && condition2
  && condition3
)
то при закомментировании condition1 у нас будет ошибка синтаксиса, которую придётся отдельно исправлять.

При написании же в таком виде:
if (
  condition1 &&
  condition2 &&
  condition3
)
ошибка синтаксиса будет при закомментировании condition3.

Ну т.е. с моей точки зрения, сценарий весьма специфический (это же не SQL, где такое сплошь и рядом), но вполне возможный.
if (
  true
  && condition1
  && condition2
  && condition3
)

Не проще ли в вашем примере (раз уж мы находимся в отладчике) просто поменять значение переменной condition1 вместо комментирования/раскомментирования и последующего перезапуска/пересборки?

Если мы находимся в отладчике, и если condition1 — переменная, то возможно и проще. Но почему вы решили, что всё именно так? :) Вместо condition1 скорее всего будет какое-то явно описанное условие, возможно даже сложное.

Или вызов метода какого-то, может вообще из внешней зависимости

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

UFO just landed and posted this here
Condition 'best == null' is always 'false'

Это вторая проверка. При первой проверке переменная best действительно пустая, но так как в цикл мы в любом случае входим, то первая проверка best == null даёт вход в условный блок и запись объекта в best.

UFO just landed and posted this here

Видать, не один я сегодня торможу )

29 февраля в Новосибирске пройдёт новая Java-конференция SnowOne

… на которую уже "все билеты проданы". Обидно, блин :)

Обидно, когда про конференцию узнаёшь из этой записи (

По 5 квизу — объяснение немного не про то


Предупреждение в целом верное. Только стоит писать не "may produce", а "will produce" (в свежих версиях это исправлено). У нас нет шанса инициализировать поле name, какая бы ни была реализация метода init(). Дело в том что объект this не утекает из конструктора. Метод init() вызывается, но на родительском объекте, который передан параметром. Из него мы никак не сможем доступиться до объекта, который сейчас конструируется. Да, init() может устанавливать name родительского объекта, но name текущего ему не доступен, а значит, мы можем быть уверены, что после вызова init() там всё ещё null.

Метод init там воообще ни при чём, там порядок вызова конструкторов важен. Т.е. при создании любого объекта дочернего класса — очерёдность вызова конструкторов такова, что первым будет вызван конструктор корневого класса, а значит определить пусть и публичную переменную в дочернем классе мы сможем только после вызова this.name.trim();

Какие-то все объяснения запутанные.
В конструкторе потомка мы не можем передать this в качестве параметра в конструктор предка, в этом вся причина.


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


Если передать из потомка this в конструктор Main, инициализировать name в init() потомка и отключить верификатор, то всё получится.

Тагир, спасибо за отличную дискуссию после выступления на Jetbrains Moscow 2019. Кстати, в этом году, похоже, подобной конференции не будет. Почему, не знаете?

Возможно, из-за неблагоприятной эпидемиологической обстановки. Но точно не знаю.

Sign up to leave a comment.