Недавно в Кубере? Сложновато?
Ребята из Рег.ру составили пошаговый гайд для начинающих DevOPS и просто любопытных. Изучаем!
Ребята из Рег.ру составили пошаговый гайд для начинающих DevOPS и просто любопытных. Изучаем!
👍4❤2🔥2👏1
👍11🔥3⚡2
Блиц-тестирование на грейд в Java
Менторы ШОРТКАТ собрали полезный небольшой тест, который поможет тебе проверить знания.
Конечно, это не определит грейд точно, но даст понять, какие темы западают. За прохождение ещё и дадут скидку на менторство.
Переходи в бот, чтобы пройти тест: @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqupXpmF
Менторы ШОРТКАТ собрали полезный небольшой тест, который поможет тебе проверить знания.
Конечно, это не определит грейд точно, но даст понять, какие темы западают. За прохождение ещё и дадут скидку на менторство.
Переходи в бот, чтобы пройти тест: @shortcut_sh_bot
Реклама. ООО "ШОРТКАТ", ИНН: 9731139396, erid: 2VtzqupXpmF
👍5🔥2
Как оптимизировать код?
Anonymous Quiz
42%
Использовать Мар для хранения скидок
52%
Использовать switch-case
0%
Добавить новые условия
3%
Применить цепочку тернарных операторов
2%
Использовать регулярные выражения
👍11🥴7☃3🔥3🤨1
This media is not supported in your browser
VIEW IN TELEGRAM
Хочешь вывести карьеру на новый уровень?
Прояви себя в Лиге Цифровой Экономики!
У нас ты:
- Станешь частью команды профессионалов, работающих над амбициозными проектами
- Получишь возможность реализовать творческий потенциал и внести свой вклад в развитие ключевых отраслей
- Будешь работать над сложными и интересными задачами, которые позволят расширить твои знания и навыки
- Сможешь влиять на развитие компании и рынка, участвуя в масштабных внедрениях
Не упусти шанс стать частью команды, которая меняет мир ИТ!
Подписывайся на наш канал и узнай все о наших вакансиях и проектах.
https://tglink.io/6b23b4b3dae1?erid=LjN8JuFb3
Реклама. ООО "ЭЙТИ КОНСАЛТИНГ". ИНН 7715744096.
Прояви себя в Лиге Цифровой Экономики!
У нас ты:
- Станешь частью команды профессионалов, работающих над амбициозными проектами
- Получишь возможность реализовать творческий потенциал и внести свой вклад в развитие ключевых отраслей
- Будешь работать над сложными и интересными задачами, которые позволят расширить твои знания и навыки
- Сможешь влиять на развитие компании и рынка, участвуя в масштабных внедрениях
Не упусти шанс стать частью команды, которая меняет мир ИТ!
Подписывайся на наш канал и узнай все о наших вакансиях и проектах.
https://tglink.io/6b23b4b3dae1?erid=LjN8JuFb3
Реклама. ООО "ЭЙТИ КОНСАЛТИНГ". ИНН 7715744096.
👍3🔥2
Что делает аннотация @CsvSource в данном тесте?
Anonymous Quiz
64%
Передаёт набор данных для выполнения параметризованных тестов
22%
Загружает данные для тестов из внешнего CSV-файла
3%
Генерирует случайные параметры для теста
2%
Осуществляет запуск тестов в определённой последовательности
9%
Изменяет поведение метода, чтобы возвращать значения из CSV
👍11🔥4❤1🏆1
🚨 Хотите знать про backend разработку больше, чем ваши коллеги? Глубоко анализировать архитектуру и предвидеть узкие места? Больше не стрессовать на system design собеседованиях?
👨🏻🎓 Меня зовут Андрей Суховицкий. Я разработчик c десятилетним опытом, tech lead, разрабатываю высоконагруженные системы. В 2021 и 2024 годах получил премию, как лучший преподаватель университета ИТМО.
🔥 На своем канале я пишу только о том, что кажется мне интересным, описываю случаи из практики. Темы, которые мне близки: java, kotlin, coroutines, многопоточное программирование, system design, реализация высоконагруженных и надежных систем. Я сам пишу все посты в моем телеграм канале, даже этот не исключение.
🧠 Мои посты затрагивают непростые темы и не всегда написаны простыми словами. Будем говорить с вами, как с профессионалами, тянуть вверх, расширять видение, заставлять задумываться и глубже анализировать пространство решений, делать небольшое усилие над собой, чтобы учиться.
💎 Присоединяйтесь к каналу, если готовы выйти на новый уровень.
👨🏻🎓 Меня зовут Андрей Суховицкий. Я разработчик c десятилетним опытом, tech lead, разрабатываю высоконагруженные системы. В 2021 и 2024 годах получил премию, как лучший преподаватель университета ИТМО.
🔥 На своем канале я пишу только о том, что кажется мне интересным, описываю случаи из практики. Темы, которые мне близки: java, kotlin, coroutines, многопоточное программирование, system design, реализация высоконагруженных и надежных систем. Я сам пишу все посты в моем телеграм канале, даже этот не исключение.
🧠 Мои посты затрагивают непростые темы и не всегда написаны простыми словами. Будем говорить с вами, как с профессионалами, тянуть вверх, расширять видение, заставлять задумываться и глубже анализировать пространство решений, делать небольшое усилие над собой, чтобы учиться.
💎 Присоединяйтесь к каналу, если готовы выйти на новый уровень.
👍8🔥3❤2
Что такое короткое замыкание логического оператора?
Логические операторы || и && лево-ассоциативны, то есть их параметры вычисляются слева направо. Если первое значение оказалось true в || или false в && – конечный результат уже предрешен, он будет тем же. В этом случае происходит так называемое «короткое замыкание» (short-circuiting) – оставшийся второй аргумент не вычисляется за ненадобностью.
Эту особенность иногда удобно эксплуатировать, например для проверки на null в одну строку:
Но иногда такая ситуация влечет за собой неожиданные плавающие баги, если второй аргумент – не переменная, а функция с побочным эффектом. Для этой ситуации введены версии операторов без короткого замыкания: | и &. Это логические вариации «битового и» и «битового или».
Вдобавок доступен оператор «исключающее или» ^. Он почти никогда не используется для булевых параметров, потому что абсолютно эквивалентен более интуитивно понятному !=. Другие битовые операторы для логических аргументов недоступны.
@javatasks #java
Логические операторы || и && лево-ассоциативны, то есть их параметры вычисляются слева направо. Если первое значение оказалось true в || или false в && – конечный результат уже предрешен, он будет тем же. В этом случае происходит так называемое «короткое замыкание» (short-circuiting) – оставшийся второй аргумент не вычисляется за ненадобностью.
Эту особенность иногда удобно эксплуатировать, например для проверки на null в одну строку:
return param != null && param.getBoolMember();
Но иногда такая ситуация влечет за собой неожиданные плавающие баги, если второй аргумент – не переменная, а функция с побочным эффектом. Для этой ситуации введены версии операторов без короткого замыкания: | и &. Это логические вариации «битового и» и «битового или».
Вдобавок доступен оператор «исключающее или» ^. Он почти никогда не используется для булевых параметров, потому что абсолютно эквивалентен более интуитивно понятному !=. Другие битовые операторы для логических аргументов недоступны.
@javatasks #java
👍9
Какой результат выведет программа?
Anonymous Quiz
6%
10
35%
11
46%
12
6%
13
6%
Когда выведет, тогда и скажу 😂
👍9🔥8
Перечислите целочисленные битовые операторы
Во-первых, стоит освежить знания о бинарном представлении целых знаковых чисел. В Java используется подход two's complement – для значения 0 все биты нули, при переполнении максимального значения на 1 получается минимальное.
Бинарные битовые операторы &, | и ^ действуют очевидным образом: выполняют побитовые «И», «ИЛИ» и «исключающее ИЛИ» (XOR) соответственно. Здесь особенно интересен XOR:
Применение к значению «исключающего или» с одним и тем же параметром два раза дает то же значение. За счет этого его можно использовать как простейшее шифрование, аргумент выступит ключом;
С помощью XOR реализуется XOR-обмен – алгоритм обмена значениями переменных без дополнительной памяти и без риска переполнения. Это также один из популярных вопросов для собеседования.
Унарный оператор битового отрицания (дополнения) ~. Эквивалентен «исключающему или» с самим собой – все биты инвертируются. ~x эквивалентно -x-1. ~0 == -1.
Битовые сдвиги: левый << правый знаковый >> и правый беззнаковый >>>. Левый операнд – что сдвигать, правый – на сколько битов.
Второй параметр, дистанция сдвига, должен быть не больше доступных разрядов – 31 для int и 63 для long. Если передано значение больше – используются младшие 5 и 7 битов соответственно. То есть для int переменной x << 33 эквивалентно x << 2.
a << b эквивалентно умножению a на 2 в степени b.
a >> b совпадает с делением на 2 в степени b, с округлением вниз. Для положительных a то же что a/pow(2,b). Для не делящихся нацело на pow(2,b) отрицательных это a/pow(2,b)-1.
Беззнаковый сдвиг вправо трактует число не как two's complement, а как беззнаковое. То есть Integer.MIN_VALUE будет сдвинут так, как будто это сдвигается число на 1 большее чем Integer.MAX_VALUE.
Беззнакового сдвига влево не существует, потому что он совпадал бы со знаковым сдвигом, и был бы избыточным.
@javatasks #java
Во-первых, стоит освежить знания о бинарном представлении целых знаковых чисел. В Java используется подход two's complement – для значения 0 все биты нули, при переполнении максимального значения на 1 получается минимальное.
Бинарные битовые операторы &, | и ^ действуют очевидным образом: выполняют побитовые «И», «ИЛИ» и «исключающее ИЛИ» (XOR) соответственно. Здесь особенно интересен XOR:
Применение к значению «исключающего или» с одним и тем же параметром два раза дает то же значение. За счет этого его можно использовать как простейшее шифрование, аргумент выступит ключом;
С помощью XOR реализуется XOR-обмен – алгоритм обмена значениями переменных без дополнительной памяти и без риска переполнения. Это также один из популярных вопросов для собеседования.
Унарный оператор битового отрицания (дополнения) ~. Эквивалентен «исключающему или» с самим собой – все биты инвертируются. ~x эквивалентно -x-1. ~0 == -1.
Битовые сдвиги: левый << правый знаковый >> и правый беззнаковый >>>. Левый операнд – что сдвигать, правый – на сколько битов.
Второй параметр, дистанция сдвига, должен быть не больше доступных разрядов – 31 для int и 63 для long. Если передано значение больше – используются младшие 5 и 7 битов соответственно. То есть для int переменной x << 33 эквивалентно x << 2.
a << b эквивалентно умножению a на 2 в степени b.
a >> b совпадает с делением на 2 в степени b, с округлением вниз. Для положительных a то же что a/pow(2,b). Для не делящихся нацело на pow(2,b) отрицательных это a/pow(2,b)-1.
Беззнаковый сдвиг вправо трактует число не как two's complement, а как беззнаковое. То есть Integer.MIN_VALUE будет сдвинут так, как будто это сдвигается число на 1 большее чем Integer.MAX_VALUE.
Беззнакового сдвига влево не существует, потому что он совпадал бы со знаковым сдвигом, и был бы избыточным.
@javatasks #java
👍9🔥4
Как узнать, является ли A подтипом B?
В Java доступны три способа проверки совместимости типов. Функционально они ничем не отличаются, применяются для разных наборов аргументов. В порядке убывания быстродействия:
instanceof – бинарный оператор, самый быстрый и самый используемый. Если есть экземпляр A и можно указать B явно, выбирать надо его. Если A (точнее тип хранящей экземпляр A переменной) и B не из одной цепочки наследования – экземпляр точно не может быть подтипом B и компиляция упадет с ошибкой inconvertible types.
Class::isInstance – метод принимает параметром объект типа A. Его стоит выбрать, когда экземпляр A в наличии, но B – неизвестный на этапе компиляции тип. То есть, для переменных A a и Class bClass, можем проверить bClass.isInstance(a).
Class::isAssignableFrom – принимает Class<A>. Единственное, что остается, если экземпляра A нет. bClass.isAssignableFrom(aClass).
Есть еще четвертый способ – имея экземпляр типа A привести его к B. Если типы были несовместимы, приведение выбросит ClassCastException. Это во всех смыслах плохой способ, построению логики программы на исключениях нет оправдания. Подробная аргументация описана в Effective Java Item 57.
В Java доступны три способа проверки совместимости типов. Функционально они ничем не отличаются, применяются для разных наборов аргументов. В порядке убывания быстродействия:
instanceof – бинарный оператор, самый быстрый и самый используемый. Если есть экземпляр A и можно указать B явно, выбирать надо его. Если A (точнее тип хранящей экземпляр A переменной) и B не из одной цепочки наследования – экземпляр точно не может быть подтипом B и компиляция упадет с ошибкой inconvertible types.
Class::isInstance – метод принимает параметром объект типа A. Его стоит выбрать, когда экземпляр A в наличии, но B – неизвестный на этапе компиляции тип. То есть, для переменных A a и Class bClass, можем проверить bClass.isInstance(a).
Class::isAssignableFrom – принимает Class<A>. Единственное, что остается, если экземпляра A нет. bClass.isAssignableFrom(aClass).
Есть еще четвертый способ – имея экземпляр типа A привести его к B. Если типы были несовместимы, приведение выбросит ClassCastException. Это во всех смыслах плохой способ, построению логики программы на исключениях нет оправдания. Подробная аргументация описана в Effective Java Item 57.
👍17🔥2
Что такое ковариантность и контравариантность?
Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.
Легче всего осознать эти понятия на примерах:
🔘 Ковариантность: List<Integer> можно присвоить в переменную типа List<? extends Number> (как будто он наследник List<Number>).
🔘 Контравариантность: в качестве параметра метода List<Number>#sort типа Comparator<? super Number> может быть передан Comparator<Object> (как будто он родитель Comparator<Number>)
Отношение типов «можно присвоить» – не совсем наследование, такие типы называются совместимыми (отношение «is a»).
Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны: List<Number> нельзя положить ни в переменную типа List<Double>, ни в List<Object>.
Массивы ковариантны: в переменную Object[] можно присвоить значение типа String[].
Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.
Формально, ковариантность/контравариантность типов – это сохранение/обращение порядка наследования для производных типов. Проще говоря, когда у ковариантных сущностей типами-параметрами являются родитель и наследник, они сами становятся как бы родителем и наследником. Контравариантные наоборот, становятся наследником и родителем.
Легче всего осознать эти понятия на примерах:
🔘 Ковариантность: List<Integer> можно присвоить в переменную типа List<? extends Number> (как будто он наследник List<Number>).
🔘 Контравариантность: в качестве параметра метода List<Number>#sort типа Comparator<? super Number> может быть передан Comparator<Object> (как будто он родитель Comparator<Number>)
Отношение типов «можно присвоить» – не совсем наследование, такие типы называются совместимыми (отношение «is a»).
Существует еще одно связанное понятие – инвариантность. Инвариантность – это отсутствие свойств ковариантности и контрвариантности. Дженерики без вайлдкардов инвариантны: List<Number> нельзя положить ни в переменную типа List<Double>, ни в List<Object>.
Массивы ковариантны: в переменную Object[] можно присвоить значение типа String[].
Переопределение методов начиная с Java 5 ковариантно относительно типа результата и типов исключений.
👍13🔥3❤2
Как работает вывод типов?
Для начала разберемся, что такое вывод типов. Type inference – это способность компилятора догадаться, какой тип нужно подставить, и сделать это за вас. На обычном интервью никто не спросит детали алгоритма вывода типов, достаточно будет сказать, что вывод происходит статически, только на основании типов аргументов и ожидаемого типа результата. По сути, вопрос заключается не в «как работает?», а «что это и когда возникает?».
Первое, что многим приходит в голову при фразе «вывод типов» – diamond operator <>. Он появился в Java с версии 7. Его применяют к конструкторам дженерик классов, чтобы отличать требование автоматического вывода типа от raw type.
С Java 9 diamond operator заработал и для анонимных классов.
Для дженерик методов можно указывать параметр явно, но diamond синтаксически недопустим – вывод и так сработает по умолчанию.
В Java 10 для вывода типа локальной переменной добавлено ключевое слово var. Работает это так же, как в большинстве современных языков – ключевое слово ставится вместо типа при объявлении.
Типы выводимых параметров лямбда-выражения также можно не указывать. С Java 11 вместо типа указывается ключевое слово var. Такой синтаксис дает возможность добавлять параметру модификаторы и аннотации.
Для начала разберемся, что такое вывод типов. Type inference – это способность компилятора догадаться, какой тип нужно подставить, и сделать это за вас. На обычном интервью никто не спросит детали алгоритма вывода типов, достаточно будет сказать, что вывод происходит статически, только на основании типов аргументов и ожидаемого типа результата. По сути, вопрос заключается не в «как работает?», а «что это и когда возникает?».
Первое, что многим приходит в голову при фразе «вывод типов» – diamond operator <>. Он появился в Java с версии 7. Его применяют к конструкторам дженерик классов, чтобы отличать требование автоматического вывода типа от raw type.
С Java 9 diamond operator заработал и для анонимных классов.
Для дженерик методов можно указывать параметр явно, но diamond синтаксически недопустим – вывод и так сработает по умолчанию.
В Java 10 для вывода типа локальной переменной добавлено ключевое слово var. Работает это так же, как в большинстве современных языков – ключевое слово ставится вместо типа при объявлении.
Типы выводимых параметров лямбда-выражения также можно не указывать. С Java 11 вместо типа указывается ключевое слово var. Такой синтаксис дает возможность добавлять параметру модификаторы и аннотации.
👍13🔥3❤2
Чем анонимный внутренний класс отличается от лямбды?
Лямбда-выражение имеет более легковесный синтаксис. Не нужно явно указывать тип функционального интерфейса, который лямбда реализует – он автоматически выведется из контекста. Лямбда-выражения добавлены в язык в первую очередь как синтаксический сахар.
С другой стороны, у класса есть поля. Экземпляр анонимного класса сохраняет свое состояние между вызовами, и меняет его при необходимости. Для лямбды доступен лишь захват и effectively final использование внешних переменных.
Лямбдой реализуется только функциональный интерфейс. Функциональный интерфейс – это тип с единственным абстрактным методом. Анонимным классом же можно расширить любой расширяемый класс или реализовать интерфейс с любым количеством абстрактных методов.
Анонимный класс создает новый скоуп, лямбда работает в текущем. Это значит, что объявление переменной с именем, которое уже используется снаружи, в лямбде вызовет ошибку компиляции «variable is already defined», в анонимном классе скроет (shadowing) внешнюю переменную.
С точки зрения реализации JVM, для лямбды не создается дополнительного .class файла, как это происходит для анонимного класса. Соответственно, не происходит и обычной загрузки и верификации класса. Вместо этого используется механизм invokedynamic и класс генерируется на лету с помощью LambdaMetafactory. Так что лямбда-выражения обычно работают быстрее.
@javatasks #java
Лямбда-выражение имеет более легковесный синтаксис. Не нужно явно указывать тип функционального интерфейса, который лямбда реализует – он автоматически выведется из контекста. Лямбда-выражения добавлены в язык в первую очередь как синтаксический сахар.
С другой стороны, у класса есть поля. Экземпляр анонимного класса сохраняет свое состояние между вызовами, и меняет его при необходимости. Для лямбды доступен лишь захват и effectively final использование внешних переменных.
Лямбдой реализуется только функциональный интерфейс. Функциональный интерфейс – это тип с единственным абстрактным методом. Анонимным классом же можно расширить любой расширяемый класс или реализовать интерфейс с любым количеством абстрактных методов.
Анонимный класс создает новый скоуп, лямбда работает в текущем. Это значит, что объявление переменной с именем, которое уже используется снаружи, в лямбде вызовет ошибку компиляции «variable is already defined», в анонимном классе скроет (shadowing) внешнюю переменную.
С точки зрения реализации JVM, для лямбды не создается дополнительного .class файла, как это происходит для анонимного класса. Соответственно, не происходит и обычной загрузки и верификации класса. Вместо этого используется механизм invokedynamic и класс генерируется на лету с помощью LambdaMetafactory. Так что лямбда-выражения обычно работают быстрее.
@javatasks #java
👍25🔥10🎉4❤1