Все с пелёнок знают о существовании String Pool 🏊♀️
Полезная вещь для экономии памяти. Но единственный ли это пул в java?
В Integer, том самом классе-обертке для самого используемого примитива, есть внутренний класс IntegerCache - пул целых чисел в промежутке [-128; 127], так как в большинстве случаев используются числа как раз в этих пределах. Он объявлен как private static. В этом внутреннем классе кэшированные объекты находятся в массиве cache[].
Кэширование выполняется при первом использовании класса-обертки. После этого вместо создания нового экземпляра (кроме явного использования конструктора, конечно), используются кэшированные объекты, JVM берет их из пула✍🏻
⬇️⬇️⬇️
И каверзный вопрос
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤4🤔2
💡 Почему приложение теряет соединение с базой данных? Разбираем на примере реальной ошибки
🔍 Ситуация:
Приложение работает, но через какое-то время начинаются странности: база данных внезапно "отказывает", в логах ошибки
JDBCConnectionException - Unable to acquire JDBC Connection
и если присмотреться - рядом еще
SocketException - Too many open files .
О каких files речь и почему это мешает подключению к БД?
Вы проверяете PostgreSQL — соединений немного (ну вдруг "too many" как-то относится к соединениям), всё в порядке. В чём же проблема?
🕵️ Ответ скрыт на уровне операционной системы:
Ошибка Too many open files говорит о том, что приложение исчерпало лимит файловых дескрипторов. Linux (на сервере с вашим приложением) выделяет каждому процессу ограниченное количество дескрипторов, которые используются не только для работы с файлами, но и для сетевых соединений (сокетов)!
Если в приложении какие-то ресурсы (например, сокеты или файлы) открываются, но не закрываются, дескрипторы "утекают". В итоге, когда приложение пытается установить новое соединение с базой данных, система просто не может выделить дескриптор для нового сокета.
⚙️ Причина оказывается не в базе, а в куче "забытых" файлов или других ресурсов.
🔧 Как избежать?
Проблема решается дисциплиной работы с ресурсами. Можно использовать автоматические механизмы языка, такие как try-with-resources, или следить за ручным закрытием.
🛠 Вывод:
Ошибка соединения с базой данных и лимит открытых файлов на первый взгляд не связаны, но на практике это замкнутая цепь. Утечки файлов → превышение лимита дескрипторов → невозможность создать сокет → сбой подключения к БД.
В следующих постах расскажем как ручками проверить количество активных, ожидающих и зависших подключений к БД.
🔍 Ситуация:
Приложение работает, но через какое-то время начинаются странности: база данных внезапно "отказывает", в логах ошибки
JDBCConnectionException - Unable to acquire JDBC Connection
SocketException - Too many open files
О каких files речь и почему это мешает подключению к БД?
Вы проверяете PostgreSQL — соединений немного (ну вдруг "too many" как-то относится к соединениям), всё в порядке. В чём же проблема?
🕵️ Ответ скрыт на уровне операционной системы:
Ошибка Too many open files говорит о том, что приложение исчерпало лимит файловых дескрипторов. Linux (на сервере с вашим приложением) выделяет каждому процессу ограниченное количество дескрипторов, которые используются не только для работы с файлами, но и для сетевых соединений (сокетов)!
Если в приложении какие-то ресурсы (например, сокеты или файлы) открываются, но не закрываются, дескрипторы "утекают". В итоге, когда приложение пытается установить новое соединение с базой данных, система просто не может выделить дескриптор для нового сокета.
⚙️ Причина оказывается не в базе, а в куче "забытых" файлов или других ресурсов.
🔧 Как избежать?
Проблема решается дисциплиной работы с ресурсами. Можно использовать автоматические механизмы языка, такие как try-with-resources, или следить за ручным закрытием.
🛠 Вывод:
Ошибка соединения с базой данных и лимит открытых файлов на первый взгляд не связаны, но на практике это замкнутая цепь. Утечки файлов → превышение лимита дескрипторов → невозможность создать сокет → сбой подключения к БД.
В следующих постах расскажем как ручками проверить количество активных, ожидающих и зависших подключений к БД.
❤6🆒3✍2
💡 Совет: как ускорить отладку
В процессе дебага нужно проверить небольшое изменение в методе, но перезапускать всё приложение ради одной строки кода — слишком долго? Используйте механизм HotSwap для быстрого внесения изменений:
1️⃣ Запускаете Debug Mode.
2️⃣ Делаете изменения в коде.
3️⃣ Заходите в меню Build - пункт Recompile 'ChangedClass.java' (или просто Ctrl+Shift+F9), в окошке жмёте Reload -> видите сообщение о том, что один класс reloaded.
4️⃣ Как ни в чем не бывало продолжаете дебажить код, но уже с изменениями.
⚠️ Ограничения:
Работает только для изменений в методах (без добавления новых полей/методов/классов).
Более сложные изменения могут потребовать использования инструментов, таких как JRebel.
🚀 Итог: вместо долгого перезапуска вы сразу видите результат изменений в работе приложения. Попробуйте — это действительно экономит время!
P.S. Речь про Idea, конечно же
В процессе дебага нужно проверить небольшое изменение в методе, но перезапускать всё приложение ради одной строки кода — слишком долго? Используйте механизм HotSwap для быстрого внесения изменений:
1️⃣ Запускаете Debug Mode.
2️⃣ Делаете изменения в коде.
3️⃣ Заходите в меню Build - пункт Recompile 'ChangedClass.java' (или просто Ctrl+Shift+F9), в окошке жмёте Reload -> видите сообщение о том, что один класс reloaded.
4️⃣ Как ни в чем не бывало продолжаете дебажить код, но уже с изменениями.
⚠️ Ограничения:
Работает только для изменений в методах (без добавления новых полей/методов/классов).
Более сложные изменения могут потребовать использования инструментов, таких как JRebel.
🚀 Итог: вместо долгого перезапуска вы сразу видите результат изменений в работе приложения. Попробуйте — это действительно экономит время!
P.S. Речь про Idea, конечно же
1🔥6❤5👍4✍2
✨Иногда в пылу разработки мы забиваем забываем об одной важной детали при работе с реляционными БД — индексах на внешних ключах
🔍Казалось бы, мелочь: зачем заморачиваться с ещё одним индексом, если сам внешний ключ уже прописан? Но именно индекс по FK способен ускорить join-запросы (а также каскадное удаление), особенно при работе с большими объёмами данных. Еще и общая нагрузка на систему снижается. В результате вы получаете более отзывчивое приложение и довольных пользователей
✅Если у вас в базе есть внешние ключи (а они есть), убедитесь, что к ним привязаны соответствующие индексы — и ваша СУБД скажет вам спасибо
upd
в комментах вскрылось, что по этому поводу говорит оф.документация по постгресу ⬇️
🔍Казалось бы, мелочь: зачем заморачиваться с ещё одним индексом, если сам внешний ключ уже прописан? Но именно индекс по FK способен ускорить join-запросы (а также каскадное удаление), особенно при работе с большими объёмами данных. Еще и общая нагрузка на систему снижается. В результате вы получаете более отзывчивое приложение и довольных пользователей
✅Если у вас в базе есть внешние ключи (а они есть), убедитесь, что к ним привязаны соответствующие индексы — и ваша СУБД скажет вам спасибо
upd
в комментах вскрылось, что по этому поводу говорит оф.документация по постгресу ⬇️
1👍6🔥6💯3
SERIAL vs GENERATED AS IDENTITY в PostgreSQL - что выбрать
В большинстве случаев id наших таблиц - это число с автоинкрементом. И под это определение идеально подходит тип SERIAL (или BIGSERIAL) - при его использовании для колонки задается тип INT (или BIGINT, аналог лонга в джаве) + последовательность с такими параметрами как начальное значение, текущее, шаг инкремента и т.д.
Но это вариант считается устаревшим.
Начиная с версии PostgreSQL 10 (т.е. довольно давно) появился более современный и гибкий способ — GENERATED [ALWAYS | BY DEFAULT] AS IDENTITY. В чём же разница?
🪗
- Под капотом создаёт отдельную SEQUENCE и использует nextval() для автоинкремента
- Не соответствует стандарту SQL и имеет ограничения в управлении последовательностью
- Всё ещё встречается в старых проектах
- ПОЗВОЛЯЕТ вставлять значения идентификатора принудительно!
🚀
- Полностью соответствует SQL:2003
- Интегрированная логика без необходимости управлять отдельной SEQUENCE
- Легко изменять параметры автоинкремента с помощью ALTER TABLE
- ЗАПРЕЩАЕТ вставлять значения идентификатора принудительно!
Чуть подробнее про п.4:
При использовании SERIAL/BIGSERIAL можно в команде UPDATE указать поле id и соответствующее значение в VALUES, и оно будет добавлено в новой строке. Но что если инкремент сиквенса потом дойдёт до этого значения (допустим, сейчас сиквенс на 100, мы вставили 200)? Он же его обойдёт? Обойдёт же?
А ничего подобного. Сиквенс на это не посмотрит, выдаст очередное значение, и операция завершится ошибкой (что-то типа "значение id = n нарушает ограничение первичного ключа").
Конечно, в стандартном сценарии работы с таблицей, тем более с помощью JPA, это не критично, но всё же.
При использовании GENERATED ... AS IDENTITY тоже можно вставлять свои значения в id, но только если ALWAYS заменить на BY DEFAULT (но тогда и нюанс с нарушением ограничения не исчезает).
Если же написать ALWAYS, то принудительная вставка своих id будет невозможна.
Кстати, пишите в комментах свои предположения - для чего может быть нужно вставлять свои id и как всё-таки избежать конфликта (чтобы сиквенс не напоролся на вставленное значение🤔🤔🤔)?
И немного про управление последовательностью (сиквенсом):
Её можно сбросить на единицу или начать с другого значения несколькими способами
напрямую изменить сиквенс
или, если используется GENERATED...IDENTITY - сделать это через alter таблицы
или, например, с подзапросом для продолжения с максимального значения на данный момент
Итог:
всё тлен, делайте какие угодно id, хоть прямо в джаве генерируйте, кому какое дело
В большинстве случаев id наших таблиц - это число с автоинкрементом. И под это определение идеально подходит тип SERIAL (или BIGSERIAL) - при его использовании для колонки задается тип INT (или BIGINT, аналог лонга в джаве) + последовательность с такими параметрами как начальное значение, текущее, шаг инкремента и т.д.
Но это вариант считается устаревшим.
Начиная с версии PostgreSQL 10 (т.е. довольно давно) появился более современный и гибкий способ — GENERATED [ALWAYS | BY DEFAULT] AS IDENTITY. В чём же разница?
🪗
CREATE TABLE some_entity (
id SERIAL PRIMARY KEY,
-- other columns
);
- Под капотом создаёт отдельную SEQUENCE и использует nextval() для автоинкремента
- Не соответствует стандарту SQL и имеет ограничения в управлении последовательностью
- Всё ещё встречается в старых проектах
- ПОЗВОЛЯЕТ вставлять значения идентификатора принудительно!
🚀
CREATE TABLE some_entity (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
-- other columns
);
- Полностью соответствует SQL:2003
- Интегрированная логика без необходимости управлять отдельной SEQUENCE
- Легко изменять параметры автоинкремента с помощью ALTER TABLE
- ЗАПРЕЩАЕТ вставлять значения идентификатора принудительно!
Чуть подробнее про п.4:
При использовании SERIAL/BIGSERIAL можно в команде UPDATE указать поле id и соответствующее значение в VALUES, и оно будет добавлено в новой строке. Но что если инкремент сиквенса потом дойдёт до этого значения (допустим, сейчас сиквенс на 100, мы вставили 200)? Он же его обойдёт? Обойдёт же?
А ничего подобного. Сиквенс на это не посмотрит, выдаст очередное значение, и операция завершится ошибкой (что-то типа "значение id = n нарушает ограничение первичного ключа").
Конечно, в стандартном сценарии работы с таблицей, тем более с помощью JPA, это не критично, но всё же.
При использовании GENERATED ... AS IDENTITY тоже можно вставлять свои значения в id, но только если ALWAYS заменить на BY DEFAULT (но тогда и нюанс с нарушением ограничения не исчезает).
Если же написать ALWAYS, то принудительная вставка своих id будет невозможна.
Кстати, пишите в комментах свои предположения - для чего может быть нужно вставлять свои id и как всё-таки избежать конфликта (чтобы сиквенс не напоролся на вставленное значение🤔🤔🤔)?
И немного про управление последовательностью (сиквенсом):
Её можно сбросить на единицу или начать с другого значения несколькими способами
напрямую изменить сиквенс
ALTER SEQUENCE some_entity_id_seq RESTART WITH 1;
или, если используется GENERATED...IDENTITY - сделать это через alter таблицы
ALTER TABLE some_entity ALTER COLUMN id RESTART WITH 1;
или, например, с подзапросом для продолжения с максимального значения на данный момент
SELECT setval('some_entity_id_seq', (SELECT MAX(id) FROM some_entity));Итог:
всё тлен, делайте какие угодно id, хоть прямо в джаве генерируйте, кому какое дело
1🔥11🤝3❤2☃1
"Как работает Хэшмапа? " - этот вопрос уже стал мемом в контексте обсуждения собеседований по джаве. Он встречается в любом списке "топ-N вопросов по Java" и звучит настолько часто, что многие стали считать это признаком низкого качества подготовки интервьюера к проведению тех.собеса.
Однако, означает ли это, что нам не надо разбираться в хэшмапе? Конечно, надо, потому что это база, а еще хорошая возможность набрать легкие баллы там, где другие теряются в деталях!
📊 equals(), hashCode() и… коллизии
Часто вопросы крутятся вокруг работы equals() и hashCode(). И тут можно попасть в ловушку терминологии, особенно когда речь заходит о коллизиях. Вот пример распространённой ошибки:
❌ "Ключи попадают в один бакет при коллизии хэшкода"
На самом деле это не совсем так. Правильнее будет сказать:
✅ "Ключи попадают в один бакет при коллизии номера бакета"
В чём разница?
Коллизия хэшкода — два разных объекта возвращают одинаковый результат метода hashCode() - это случается довольно редко.
Коллизия бакета — два объекта (неважно, одинаковый у них хэшкод или нет) попадают в один и тот же бакет в HashMap.
И вот важный момент: для коллизии бакета НЕ НУЖНА коллизия хэшкода
🚀 Как определяется номер бакета?
При добавлении элемента (пары ключ-значение) в HashMap определяется хэшкод ключа, а далее по сути находится остаток от его деления на количество бакетов с помощью таких операций:
где n — это размер массива бакетов (всегда степень двойки - 16, 32, 64 etc).
И так как количество бакетов невелико, для разных ключей может быть вычислен один и тот же результат. И вот это уже и есть коллизия бакета
🔑 Наглядный пример:
если бакетов 16, то ключи
- "1" и "17" попадут вместе в один бакет (хотя очевидно, что хэшкод у них абсолютно разный), а следом за ними пойдут еще "33", "49", "65" и т.д. с шагом в 16 единиц;
- "2", "18", "34", "50"... - вместе в следующий бакет
Итоги:
- Коллизия хэшкода != коллизия бакета
- Для распределения по бакетам важен не сам хэшкод, а результат функции распределения
- Понимание этой разницы — не просто "мемный вопрос", а демонстрация того, насколько вы погрузились в тему
В следующих постах расскажу и про другие неочевидные вещи, связанные с коллекциями
Однако, означает ли это, что нам не надо разбираться в хэшмапе? Конечно, надо, потому что это база, а еще хорошая возможность набрать легкие баллы там, где другие теряются в деталях!
📊 equals(), hashCode() и… коллизии
Часто вопросы крутятся вокруг работы equals() и hashCode(). И тут можно попасть в ловушку терминологии, особенно когда речь заходит о коллизиях. Вот пример распространённой ошибки:
❌ "Ключи попадают в один бакет при коллизии хэшкода"
На самом деле это не совсем так. Правильнее будет сказать:
✅ "Ключи попадают в один бакет при коллизии номера бакета"
В чём разница?
Коллизия хэшкода — два разных объекта возвращают одинаковый результат метода hashCode() - это случается довольно редко.
Коллизия бакета — два объекта (неважно, одинаковый у них хэшкод или нет) попадают в один и тот же бакет в HashMap.
И вот важный момент: для коллизии бакета НЕ НУЖНА коллизия хэшкода
🚀 Как определяется номер бакета?
При добавлении элемента (пары ключ-значение) в HashMap определяется хэшкод ключа, а далее по сути находится остаток от его деления на количество бакетов с помощью таких операций:
key.hashCode() ^ (h >>> 16)
(n - 1) & hash
где n — это размер массива бакетов (всегда степень двойки - 16, 32, 64 etc).
И так как количество бакетов невелико, для разных ключей может быть вычислен один и тот же результат. И вот это уже и есть коллизия бакета
🔑 Наглядный пример:
если бакетов 16, то ключи
- "1" и "17" попадут вместе в один бакет (хотя очевидно, что хэшкод у них абсолютно разный), а следом за ними пойдут еще "33", "49", "65" и т.д. с шагом в 16 единиц;
- "2", "18", "34", "50"... - вместе в следующий бакет
Итоги:
- Коллизия хэшкода != коллизия бакета
- Для распределения по бакетам важен не сам хэшкод, а результат функции распределения
- Понимание этой разницы — не просто "мемный вопрос", а демонстрация того, насколько вы погрузились в тему
В следующих постах расскажу и про другие неочевидные вещи, связанные с коллекциями
1👍12🔥9🤝2❤1
📔 Книга "Чистый код" начинается с иллюстрации единственной надежной метрики качества кода - количество "чертей" в минуту 👹/m
Сразу небольшое отступление.
знаете, когда написана эта книга? Шок - 2008 год! При этом прямо в первой главе Боб Мартин пишет:
Дальше он, конечно же, опровергает это мнение. Но это 2008 год - за 14 лет до хайпа chatGPT etc. Вообще подобные разговоры велись чуть ли не всю историю программирования... но это уже
совсем другая история.
🤌 Вернемся к качеству кода.
Далее в главе 3 "Функции" он пишет, что аргументы-флаги (то есть булевы значения) "уродливы", а передача логического значения в метод - ужасная привычка.
Почему?
Потому что сигнатура метода становится менее понятной, а сам метод выполняет две разных операции (в зависимости от флага) вместо одной.
В этом случае он рекомендует разбивать такой метод на два метода (без boolean-параметров), давая каждому методу соответствующее понятное название.
Возможно(совершенно точно) , кто-то может поспорить с этим, но пока идём дальше.
📘Что говорит Джош Блох в своём "Эффективном программировании"?
У него тоже есть совет разбивать методы, но, правда, в другой ситуации - когда у исходного метода слишком много параметров - больше четырёх
(это только один из трех способов исправления ситуации с большим количеством параметров, а кроме него - использование вспомогательного класса с набором параметров, и использование билдера).
А что насчет boolean? Блох тоже отговаривает от таких сигнатур методов, предлагая взамен...
🫨 ЭНАМЫ с двумя элементами!
Пример:
Какие плюсы:
1️⃣ сразу понятнее - и название энама, и сами значения несут явный смысл
2️⃣ в любой момент можно добавить в энам новые значения без лишних телодвижений (приводится пример - TemperatureScale.KELVIN).
Если метод написан хорошо, то его, возможно, вообще не придется трогать. Принцип open-closed в действии?
Пример с шкалами температур, мне кажется, не совсем удачный, но смысл ясен.
3️⃣ вероятно, количество чертей станет ближе к левой двери с картинки, чем к правой
👀Итог:
выбрать какой-то из приведенных способов (по Мартину или по Блоху), или же написать метод, принимающий 5 boolean-аргументов - как всегда, зависит от конкретной ситуации и от положения Марса в пятом доме. Но лучше знать об этих вариантах, чтобы было из чего выбирать
Сразу небольшое отступление.
знаете, когда написана эта книга? Шок - 2008 год! При этом прямо в первой главе Боб Мартин пишет:
[...] Нам даже доводилось слышать мнение, что [...] скоро весь код будет генерироваться, а не писаться вручную. Что программисты станут попросту не нужны, потому что бизнесмены будут генерировать программы по спецификациям.
Дальше он, конечно же, опровергает это мнение. Но это 2008 год - за 14 лет до хайпа chatGPT etc. Вообще подобные разговоры велись чуть ли не всю историю программирования... но это уже
совсем другая история.
🤌 Вернемся к качеству кода.
Далее в главе 3 "Функции" он пишет, что аргументы-флаги (то есть булевы значения) "уродливы", а передача логического значения в метод - ужасная привычка.
Почему?
Потому что сигнатура метода становится менее понятной, а сам метод выполняет две разных операции (в зависимости от флага) вместо одной.
В этом случае он рекомендует разбивать такой метод на два метода (без boolean-параметров), давая каждому методу соответствующее понятное название.
Возможно
📘Что говорит Джош Блох в своём "Эффективном программировании"?
У него тоже есть совет разбивать методы, но, правда, в другой ситуации - когда у исходного метода слишком много параметров - больше четырёх
(это только один из трех способов исправления ситуации с большим количеством параметров, а кроме него - использование вспомогательного класса с набором параметров, и использование билдера).
А что насчет boolean? Блох тоже отговаривает от таких сигнатур методов, предлагая взамен...
🫨 ЭНАМЫ с двумя элементами!
Пример:
public enum TemperatureScale { FAHRENHEIT, CELSIUS }Какие плюсы:
1️⃣ сразу понятнее - и название энама, и сами значения несут явный смысл
doSomething(TemperatureScale.CELSIUS);
// vs
doSomething(true);
2️⃣ в любой момент можно добавить в энам новые значения без лишних телодвижений (приводится пример - TemperatureScale.KELVIN).
Если метод написан хорошо, то его, возможно, вообще не придется трогать. Принцип open-closed в действии?
Пример с шкалами температур, мне кажется, не совсем удачный, но смысл ясен.
3️⃣ вероятно, количество чертей станет ближе к левой двери с картинки, чем к правой
👀Итог:
выбрать какой-то из приведенных способов (по Мартину или по Блоху), или же написать метод, принимающий 5 boolean-аргументов - как всегда, зависит от конкретной ситуации и от положения Марса в пятом доме. Но лучше знать об этих вариантах, чтобы было из чего выбирать
1🔥13👏2💯1
Кстати, какие книги считаете маст рид?
Anonymous Poll
23%
Чистый код, Боб Мартин
21%
Java. Эффективное программирование, Джош Блох
16%
Философия Java, Брюс Эккель
21%
Java. Полное руководство/Руководство для начинающих, Герберт Шилдт
5%
Java. Библиотека профессионала, Кей Хорстманн
9%
Книга с поездами
21%
Книга с кабанчиком
5%
Алгоритмы на Java, Роберт Седжвик, Кевин Уэйн
12%
Spring in action
16%
Аксиома Эскобара по всем пунктам
Многие знают про плагин Key Promoter X, но я считаю его скорее вредным.
Он вроде бы полезен - подсказывает горячие клавиши, но на самом деле отслеживает далеко не все ситуации, когда вы делаете что-то мышкой и глазами, а могли бы использовать шорткаты. Таким образом, создается иллюзия, что он вам поможет, но помощь эта неэффективна.
Намного лучше взять с сайта жетбрейнс официальный keymap (на картинке).
Там много всего, сходу может выглядеть страшно, поэтому предлагаю пробежаться по реально полезным штукам для повседневной работы:
Работа с вкладками
↔️ Ctrl + Tab – переключение между вкладками (там еще разные пункты есть кроме открытых вкладок, посмотрите сами)
🔂 Alt + Left/Right - переключение по соседним вкладкам влево/вправо
⏹️ Ctrl + F4 – закрытие вкладки (очень удобно когда в ходе работы наоткрывалось много, а после нужно все закрыть)
Навигация
⬅️➡️ Ctrl + Alt + Left/Right – переход назад/вперед по истории переходов (это прям самая имба - возвращаетесь назад в том порядке, каким попали в текущее место в коде - например, при переходе по вызовам методов или объявлению переменных)
🔀 Ctrl + Shift + Backspace – переход к последнему изменению (тоже очень полезно)
🔢 Ctrl + E – переключение между последними использованными файлами (похоже на переключение между вкладками, но включает и уже закрытые)
Работа с закладками
⏸️ F11 – поставить обычную закладку на строке /убрать любую закладку
#️⃣ Shift + F11 – открыть список всех закладок.
⏺️ Ctrl + F11 – поставить пронумерованную закладку (легче ориентироваться, чем с обычными)
↗️ Ctrl + <номер> – переход к пронумерованной закладке (например, Ctrl + 1)
Использование таких приемов действительно делает работу проще и быстрее
Он вроде бы полезен - подсказывает горячие клавиши, но на самом деле отслеживает далеко не все ситуации, когда вы делаете что-то мышкой и глазами, а могли бы использовать шорткаты. Таким образом, создается иллюзия, что он вам поможет, но помощь эта неэффективна.
Намного лучше взять с сайта жетбрейнс официальный keymap (на картинке).
Там много всего, сходу может выглядеть страшно, поэтому предлагаю пробежаться по реально полезным штукам для повседневной работы:
Работа с вкладками
↔️ Ctrl + Tab – переключение между вкладками (там еще разные пункты есть кроме открытых вкладок, посмотрите сами)
🔂 Alt + Left/Right - переключение по соседним вкладкам влево/вправо
⏹️ Ctrl + F4 – закрытие вкладки (очень удобно когда в ходе работы наоткрывалось много, а после нужно все закрыть)
Навигация
⬅️➡️ Ctrl + Alt + Left/Right – переход назад/вперед по истории переходов (это прям самая имба - возвращаетесь назад в том порядке, каким попали в текущее место в коде - например, при переходе по вызовам методов или объявлению переменных)
🔀 Ctrl + Shift + Backspace – переход к последнему изменению (тоже очень полезно)
🔢 Ctrl + E – переключение между последними использованными файлами (похоже на переключение между вкладками, но включает и уже закрытые)
Кстати, в Идее у многих шорткатов есть еще и действие на второе нажатие! Попробуйте нажать Ctrl + E несколько раз - увидите разницу (показывает последние использованные файлы/последние измененные файлы)
Работа с закладками
⏸️ F11 – поставить обычную закладку на строке /убрать любую закладку
#️⃣ Shift + F11 – открыть список всех закладок.
⏺️ Ctrl + F11 – поставить пронумерованную закладку (легче ориентироваться, чем с обычными)
↗️ Ctrl + <номер> – переход к пронумерованной закладке (например, Ctrl + 1)
Использование таких приемов действительно делает работу проще и быстрее
1🔥15👍4❤2🥱1
Всем привет! Пост не технический.
Сегодня завершилось моё преподавание дисциплин Java Core и SQL в замечательной группе мотивированных и старательных учеников. Эти полгода мы тщательно разбирали базу, учились применять её в своих проектах, рассматривали реальные кейсы и готовились к тем сюрпризам, которые ждут на собеседованиях и в работе.
Большое спасибо всем за ваше внимание, активное участие и правильные вопросы, было круто, я и сам учился вместе с вами))
Буду рад увидеть здесь ваши отзывы. Что запомнилось? Что было полезно? Что можно было сделать лучше? В общем, пишите всё, что думаете. Остаёмся на связи! 😊
Сегодня завершилось моё преподавание дисциплин Java Core и SQL в замечательной группе мотивированных и старательных учеников. Эти полгода мы тщательно разбирали базу, учились применять её в своих проектах, рассматривали реальные кейсы и готовились к тем сюрпризам, которые ждут на собеседованиях и в работе.
Большое спасибо всем за ваше внимание, активное участие и правильные вопросы, было круто, я и сам учился вместе с вами))
Буду рад увидеть здесь ваши отзывы. Что запомнилось? Что было полезно? Что можно было сделать лучше? В общем, пишите всё, что думаете. Остаёмся на связи! 😊
1🔥9🥰2👏2😢1