Javanese Online
Open in Telegram
Статьи и новости, наблюдения и советы. Кодревью: http://javanese.online/%D1%80%D0%B0%D0%B7%D0%B1%D0%BE%D1%80_%D0%BA%D0%BE%D0%B4%D0%B0/ Обсуждение в @javanese_questions Материалы пишет @Harmonizr
Show more723
Subscribers
No data24 hours
+37 days
+530 days
Posts Archive
Отгадка заключается в том, что создание (неинициализированного) объекта и вызов его конструктора — это две разные инструкции.
private static SomeComponent inPlace(
java.util.concurrent.Future<java.lang.String>
) throws java.lang.Exception;
// выделение памяти
0: new SomeComponent
...
// вызов конструктора
13: invokespecial SomeComponent."<init>":(Ljava/lang/String;)V
16: areturn
private static SomeComponent withVariable(
java.util.concurrent.Future<java.lang.String>
) throws java.lang.Exception;
...
//выделение памяти
10: new SomeComponent
13: dup
14: aload_1
// вызов конструктора
15: invokespecial SomeComponent."<init>":(Ljava/lang/String;)V
18: areturn
если считать, что фьюча ещё не выполнена, а класс SomeComponent ещё не загружен, то первый вариант сначала загружает класс, а потом блокируется в ожидании фьючи. Второй вариант сначала блокируется на ожидании, а потом загружает класс.
Поэтому я считаю, что первый вариант быстрее.Половина ответа на вопрос:
private static SomeComponent inPlace(
java.util.concurrent.Future<java.lang.String>
) throws java.lang.Exception;
0: new SomeComponent
3: dup
4: aload_0
5: invokeinterface java/util/concurrent/Future.get:()Ljava/lang/Object;
10: checkcast class java/lang/String
13: invokespecial SomeComponent."<init>":(Ljava/lang/String;)V
16: areturn
private static SomeComponent withVariable(
java.util.concurrent.Future<java.lang.String>
) throws java.lang.Exception;
0: aload_0
1: invokeinterface java/util/concurrent/Future.get:()Ljava/lang/Object;
6: checkcast class java/lang/String
9: astore_1
10: new SomeComponent
13: dup
14: aload_1
15: invokespecial SomeComponent."<init>":(Ljava/lang/String;)V
18: areturnЕсть идеи, какой код отработает быстрее?
HeavyComponent inPlace(Future<String> f1) throws Exception {
return new HeavyComponent(f1.get());
}
HeavyComponent withVariable(Future<String> f1) throws Exception {
String s1 = f1.get();
return new HeavyComponent(s1);
}
Считаем, что это инициализация графа зависимостей, а HeavyComponent — увесистый класс.Hype-driven Android-development
Коротко о том, куда катится индустрия и с чем придётся столкнуться инженеру при поиске проектов и коллег.
Я серьёзно подумал над своим поведением.
С сегодняшнего дня буду уделять больше времени JEE, рефлексии, кодогенерации, спрингу, хибернейту, руму, даггеру, мокси, Android Architecture Components, RxJava — ведь это самые прекрасные проявления джавы, которые заслуживают большего внимания.
BitSet
Странный предмет. По определению это вектор булеанов, специализированная версия
List<Boolean>. По факту же от нормального листа эта штука очень сильно отличается:
— не реализует ни Collection, ни List;
— метод для узнавания размера называется length(), а size() возвращает немного другое значение;
— методов add и remove нет;
— метод set(length + x) не бросает исключение, а работает как add;
— запись значений false в конец уменьшает length().О выборе технологий
У любой развивающейся софтины есть лидер, формальный или неформальный. Он неплохо себе представляет, как нужно делать; может обсуждать с командой какие-то решения, но последнее слово остаётся за ним.
Можно (и нужно!) регулярно проводить аудит, чтобы узнать, всё ли делается правильно. По результатам можно выдвинуть какие-нибудь рацпредложения или даже задуматься о смене лидера.
Если компания большая, разных проектов много. Лидеры могут общаться между собой, обмениваться опытом. Можно выделять общий код в библиотеки и делиться ими внутри компании (а лучше — и снаружи!), тем самым создавая добровольное единство, полезное и удобное для всех.
Каждый проект живёт в своей устоявшейся колее. Есть верный способ всё сломать — привлечь «экспертов», которые решат за всех. Лидеры, которые внимательно выбирали решения, и команды, которые согласны с этими решениями, раз там работают, будут поставлены перед фактом: теперь всё будет иначе.
Так можно одним махом, резко и стремительно переоткрыть сотни вакансий.
new Sub("whatever"), очевидно, выведет null, потому что конструктор суперкласса вызывается раньше, чем this.value = value.
Анонимная же версия выведет "anonymous". Представить анонимный класс можно как-то так:
final class Sample$1 extends Super {
final synthetic String val$value;
Sample$1(String value) {
this.val$value = value;
super();
// конструктор суперкласса вызывается
// после инициализации собственных полей!
}
String invoke() {
return this.val$value;
}
}Сегодня на работе встретил такой паззлер.
class Super {
Super() {
System.out.println(invoke());
}
String invoke() {
return "not overridden";
}
}
class Sub extends Super {
private final String value;
Sub(String value) {
this.value = value;
}
@Override String invoke() {
return value;
}
}
...
void callSite1() {
new Sub("normal class");
}
void callSite2() {
final String value = "anonymous";
new Super() {
@Override String invoke() {
return value;
}
};
}
Оба наследника выглядят идентично. После компиляции-декомпиляции они неотличимы. Но есть один нюанс.Я уже рекомендовал и хвалил Effective Java и в уроках ссылался на тезисы из этой книги. Пришло время сформулировать критику. Пойду по оглавлению третьего издания.
Item 2: Consider a builder when faced with many
constructor parameters
Билдеры провоцируют лишнее копирование объектов. Нет адекватного способа указывать обязательные параметры. Кроме самого класса нужно поддерживать ещё и билдер. Кажется, зачастую лучше будет нарезать объект на более мелкие, чтобы снова было удобно использовать конструкторы.
Item 3: Enforce the singleton property with a private
constructor or an enum type
Идея использовать
enum чтобы защититься от рефлективного создания нескольких экземпляров синглтона бредова: от кривых/шаловливых рук это не помогает, а вдобавок синглтон становится Comparable и Serializable, что ещё более дико.
Item 13: Override `clone` judiciously
Я бы назвал 'Never override clone at all'. В целом посыл такой же, придрался только к названию раздела.
Item 39: Prefer annotations to naming patterns
Да, аннотация @Test — хороший пример (хотя можно было обойтись публичными воидовыми методами без параметров), но все остальные применения называются «хочется странного». Annotation-driven development зашёл слишком далеко.
Item 41: Use marker interfaces to define types
Nope. Serializable — неудачная аннотация, являющаяся частью ещё более неудачного механизма. Маркер-интерфейсы не нужны.
Item 78: Synchronize access to shared mutable data
Я бы считал, что разделять данные между потоками не нужно вовсе. Либо есть пулы потоков и фьючи (или акторы с каналами), либо низкоуровневая lock-free дичь.В итоге какие-то комментарии со временем всё же появились, какие-то — нет.
Короче, я бережно скопировал все четыре ваших комментария в табличку, а новые можно оставлять, залогинившись через гитхаб.
Ну всё, теперь можно спокойно дописывать статью, в комментариях к которой будет гореть.
Считаю поддержку комментариев крайне важной частью любого информационного сайта.
Нет комментариев → нет возможности обсуждать неточности и исправлять ошибки и заблуждения → материал не развивается и ловить там нечего.
Ещё до появления этого канала и соседнего чата у меня был виджет комментариев ВК. Всё работало как надо, пока не начали появляться комментарии: их было видно только мне, модератору, но для остальных пользователей они не появлялись. Если бы я нарочно, это была бы невероятная подлость. Что характерно, на другом моём сайте всё работает.
Я перепроверил всё, что мог перепроверить, и пошёл в поддержку, в красках описав, что делаю, чего ожидаю и что происходит. В ответ мне предложили перепроверить всё то, что я перечислил в своём обращении...
Комментарии через GitHub
public poll
да – 21
👍👍👍👍👍👍👍 70%
@zsavely, @whalemare, @fm_norton, @seconds_grate, @Restorm, @TazmanOne, @LionZXY, @denis_amr, @martitrofan, @nikitafallen, @aleshka_r, Anvar, @fixerteam, @serg_chuprin, @aig2100, @vitkidd, Vlad, @marshmellome, @Usmanskey, @zdrastepoka, @ckpenep
всё равно – 9
👍👍👍 30%
@GlebKl, @alexey_mileev, @bouncepaw, @nullsafety, @BBDDBA, @KarapetianDav, @NikiJava, @jamakasi667, @vlad0956
нет
▫️ 0%
👥 30 people voted so far.
Сейчас виджет комментариев на javanese.online практически не работает, скоро там должен прорасти новый.
Верно ли я понимаю, что наиболее уместный способ авторизации — GitHub? Есть ли готовый виджет, который это поддерживает, или придётся хранить комментарии у себя?
Жду ваших ответов и мнений в @javanese_questions.
Программное обеспечение отстаёт от аппаратного
Вы часто встречаете глючные процессоры? Я — нет: помню только уязвимости Meltdown и Spectre. В остальном — процессоры шустрые, умеют предсказывать ветвление, спекулятивно выполнять код, кешировать часто используемую память. Каждый новый процессор выполняет старый код быстрее, затрачивая при этом меньше электроэнергии. Всё это — при постоянно увеличивающейся сложности схемы и сохранении обратной совместимости.
Новые же операционные системы занимаются тем, что копируют друг у друга дизайн и занимают всё новые гигабайты места. Программисты изобретают новые фреймворки, которые решают уже решённые (или вовсе не существовавшие) проблемы. Повышают уровень абстракций, не уменьшая количество кода, не улучшая ни его читаемость, ни выразительность, ни, тем более, быстродействие.
Раньше многие забивали на понимание того, как работают процессор и память. Сейчас — на то, как устроены язык и рантайм.
Далеко пойдём, ребята.
Интерфейс с единственной реализацией — частый антипаттерн в enterprise-разработке.
Избыточный, а при определённых правилах именования — ещё и страшный, он замедляет вкатывание в проект и не приносит пользы.
Каждой задаче — по языку
Я вижу как минимум два способа понимать это высказывание.
Первый (назовём его горизонтальным) предполагает, что для каждой прикладной области есть наиболее подходящий язык программирования. Например, для серверной разработки — Java, для яблок — Swift, для Android — Kotlin, для фронта — TypeScript, для системщины — Си.
Второй (назовём вертикальным) делит языки на прикладные и низкоуровневые. Например, сервер — Kotlin-JVM, Android — Kotlin-JVM/Android, яблоки — Kotlin-Native, фронт — Kotlin-JVM. Написание ОС и драйверов — Rust.
Или, например, сервер и Android — Clojure, яблоки (в React-Native) и фронт — ClojureScript, Android — Clojure.
Или сервер — Haskell, Android — Haskell (NDK или Frege), iOS и фронт — PureScript.
Мне кажется, что правильный способ понимать это высказывание — второй, т. к. нет объективных причин для каждой платформы (прикладной сферы) заводить отдельный язык.
https://github.com/googlesamples/android-architecture/blob/todo-mvp-rxjava/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/util/schedulers/SchedulerProvider.java#L23
Почему-то некоторые очень беспокоятся, что без необходимости будет создан лишний объект. Единственный экземпляр, да ещё и без полей.
В данной ситуации, наоборот, следует подумать о том, что верифицировать, загрузить класс и скомпилировать его методы — многократно дороже.
Очевидный способ писать понятный и поддерживаемый код: неизменяемые данные и чистые функции.
К сожалению, это не работает: изменяемое состояние так или иначе существует, а если его не видно, значит, оно спрятано за фреймворком.
Самый простой способ работать с изменяемыми данными — сделать их обзёрвабельными. Собственно, именно этим и занимаются фреймворки вроде Redux, как бы предоставляя map/reduce и применяя наши функции к данным.
