• ,

Найти IT Санкт-Петербург!

Жаварашовцы из Питера, те кто смог попасть на форум, обращаюсь к вам)))
Давайте MeetUp-немся перед началом event-a.
Узнаем, что, как и каким образом смог или нее смог добиться успеха.
Кто как не мы можем изменить этот мир!

Пожалуй оставлю свой Telegram: @vodka_balalayka. Пишите и будете отвеченными)
Обязательно отписывайтесь в комментариях.

Регистрируйтесь на сайте.

Коротко о сабже:
  • ,

+1 Java developer

Добрый вечер всем ученикам JavaRush, которые проводят уйму времени за решением задач, проклиная ненавистный popup «Программа не прошла тестирование». Придя в очередной раз с работы, решил написать все-таки свою историю, которая уверен до боли похожа на многие другие истории учеников.

На данный момент я уже полтора года работаю Java программистом в одной из киевских компаний. Занимаемся довольно серьезными и интересными вещами.

Начиналось все скорее всего так-же, как и у многих других студентов 5-6 курса, которые начинают уже задумываться что его делать после окончания. Когда приходит осознание того, что та работа, которой занимался со второго курса, особо таких перспектив на которые рассчитываешь, не имеет. И приходит понимание того, что кроме программирования, в универе другие предметы тебя так не цепляли.

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

И это честно говоря давало еще больше мотивации учиться самому и постепенно забивать на универ (за что кстати чуть не выгнали с магистратуры, но даже если б и выгнали, особо не жалел бы). Настолько бесполезным тогда казался универ, что было ощущение что там просто напросто тратишь свое драгоценное время, за которое мог бы пройти половину уровня и получить кучу реального практического опыта, о котором в универе думать не приходится.

Поэтому главным на том этапе было решить как можно больше задач. Когда был на уровне 19-20, ребята сделали реальный проект «Рейтинги». Было безумно приятно увидеть что делают люди на несколько уровней выше тебя, с которыми часто переписываешься и консультируешься на info. И конечно же сразу захотелось войти в ТОП по решенным задачам.

После 27 уровня задачи почти закончились. Выхода было два — идти на реальный проект JavaRush, либо бороться за интернатуру в одной из ИТ компаний Украины. После нескольких собеседований и тестирований, подготовка к которым была целыми днями без выходных, посчастливилось попасть в одну их них. На английский тогда кстати сделал очень большой упор, целыми днями сидел разбирал типичные разговоры на собеседованиях по английски.

И только после интернатуры, когда получил минимальный практический опыт с Git, Spring, Spring MVC, Hibernate, REST, JPA, JSP, MySQL, TomCat, jUnit, Spring Testing, была возможность пытаться на позиции Java Junior Programmer.

Несколько месяцев назад получил рассылку от JavaRush с вопросами. Одним из них был — «Если бы вы знали о JavaRush в самом начале обучения то, что знаете сейчас, сколько бы вы были готовы заплатить?». Ответ был $500, хотя в свое время ушло около $150. И не потому что знаю о примерных зарплатах в этой сфере. Дело скорее в человеческой жадности, если ты заплатил за это не малые деньги, то тебя жаба задавит если весь день ты ничего не учил. А мотивация это по моему самая главная движущая сила в обучении.

Именно поэтому и захотелось написать историю — как мотивацию учиться для всех тех, кто готов экран разбить когда видит очередное мать его «Программа не прошла тестирование».

Спасибо что дочитали до конца!

Автор: https://vk.com/id8743837
  • ,

Побайтовая работа с файлами

Special for Spiker

Начнем'c.
В 18 уровне начались первые задачи побайтного чтения файлов:
Прочитать файл, далее найти минимальные/максимальные байты или вывести в упорядоченном виде и т.п.

Народ тут весьма ушлый. Знают про коллекции и про то, что они могут сортировать, вставлять.
Коллекции — мощный механизм. И многие не применяли их вообще до JavaRush-а.
Оно, конечно, похвально изучать их и пытаться приткнуть куда не попадя.

И так. Возьмем задачу, которой нет в заданиях (чтобы не было спойлеров при решении), но есть сильно похожие:

Ввести с консоли имя файла
Считать все байты из файла.
Не учитывая повторений — отсортировать их по байт-коду в убывающем порядке.
Вывести на экран
Закрыть поток ввода-вывода

Пример байт входного файла
44 83 44

Пример вывода
83 44


Мы дополнительно завели переменные startTime и finishTime — чтобы засечь время выполнения программы.
Для вычисления использовал i3-3GHz/8Gb RAM/HDD WD Blue-1Tb/Win7-64/jdk-8u73-windows-x64

(примеры программ в вариантах 1-2 взяты из форума info.javarush, они чуть модифицированы только для сортировки в возрастающем порядке — то есть они РЕАЛЬНЫЕ!!)

Решаем в лоб:
// Вариант 1. Загоняем в коллекцию и сортируем используя ее метод Collections.sort 
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());
        long startTime = System.currentTimeMillis();
        
        ArrayList<Integer> listData = new ArrayList<Integer>();
        while (inputStream.available() > 0) listData.add(inputStream.read());
        inputStream.close();
        ArrayList<Integer> result = new ArrayList<Integer>(new HashSet<Integer>(listData));
        Collections.sort(result);

        while (!result.isEmpty()) {
            System.out.print(result.get(result.size()-1) + " ");
            result.remove(result.get(result.size()-1));
        }

        long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}

Решает все замечательно! Тест (если бы был — прошелся бы на ура).
Но в жизни мало файлов содержащих только строчку «Мама мыла раму».
Давайте скормим нашей программе файл в 46Мб (по нынешним меркам вроде и не особо много).
Что такое, программа выполняется 220 секунд.
Попытка скормить с вечера 1Gb файл (размер MPEG4 фильма не в самом лучшем качестве) не увенчалась успехом.
Программа утром все еще читала — а мне идти на работу уже.

В чем проблема? Наверное в использовании
ArrayList<Integer>
у которого внутри 1 миллиард элементов. Каждый элемент его занимает 16 байт минимум (Заголовок: 8 байт + Поле int: 4 байта + Выравнивание для кратности 8: 4 байта). Итого мы добровольно загоняем в память 16 Gb данных при размере оперативы в 8.

Будем делать лучше. Нырнем в коллекции глубже. И ура, нашлось то, что нам нужно.

Встречаем TreeSet

Это множество:
-не допускает хранение двух одинаковых элементов (а значит мы будем хранить в памяти все 255 элементов, вместо миллиарда!)
-при манипуляциях со своими элементами автоматом упорядочивает (само сортирует — вот он, верх совершенства!)

Получаем:
// Вариант 2. Загоняем в ТreeSet который сам сортирует (лютый win!)
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        byte[] arrBytes = new byte[256];
        long startTime = System.currentTimeMillis();

        SortedSet<Integer> list = new TreeSet<Integer>();
        while(inputStream.available()>0) list.add(inputStream.read());
        inputStream.close();

        while (!list.isEmpty())        {
            System.out.print(list.last() + " ");
            list.remove(list.last());
        }

		long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}


Имеем на выходе:
46Мб файл 176 секунд.
1Gb файл — 3 часа 5 минут.
Прогресс на лицо. Мы смогли «дождаться» результатов, да и 46Мб файл заметно быстрее обрабатывается.

Идем дальше. Давайте попытаемся отказаться от коллекций (это будет для некоторых мучительно больно). Будем использовать простые массивы (это так примитивно).
Заметим одну важную вещь. Кол-во встречающихся байт можно загнать в массив длиной 256.
Так просто будем увеличивать на единицу соответствующий считанному байту элемент массива.

Массив — побайтно

// Вариант 3. Считываем массив побайтно.
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        long startTime = System.currentTimeMillis();
        
        while (inputStream.available() > 0) arrBytes[inputStream.read()]++;

		inputStream.close();
        // Выводим отсортированный по байт-коду в обратном порядке
        for (long i = 255; i >= 0 ; i--)
            if (arrBytes[(int) i] > 0) System.out.print(i + " ");

			long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}


Имеем на выходе:
46Мб файл 158 секунд.
1Gb файл — 2 часа 55 минут.
Опять улучшение, но небольшое. И мы сделали все простыми инструментами. Не использовали микроскоп для забивания гвоздей.

Теперь лирическое отступление.
Вспомним устройство компьютера.
Память ОЗУ (DRAM) где обычно выполняется программа и хранятся переменные имеет высокую скорость доступа, но небольшой размер.
Память на жестком/flash диске (HDD или Flash-накопители) где обычно хранятся файлы, наоборот имеет низкую скорость доступа, но большой размер.
Так что когда мы побайтно читаем 1Gb файл (то есть миллиард раз обращаемся к HDD) — мы тратим много времени на работу с низкоскоростным устройством
(по песчинке перекладываем песок с кузова КамАЗа в песочницу).

Попробуем еще улучшить.

Вывалим сразу ВЕСЬ КамАЗ с песком за один раз!

// Вариант 4. Считываем массив сразу целиком за раз в память.
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        long startTime = System.currentTimeMillis();
        
        byte fileImage[]=new byte[inputStream.available()];
        long fileSize=fileImage.length;
        inputStream.read(fileImage);
        for (int i = 0; i <fileSize ; i++) arrBytes[fileImage[i] & 0b11111111]++;

		inputStream.close();
        // Выводим отсортированный по байт-коду в обратном порядке
        for (long i = 255; i >= 0 ; i--)
            if (arrBytes[(int) i] > 0) System.out.print(i + " ");

		long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}

небольшое, но опять таки важное отступление
Заметим:
1. индекс у arrBytes определен в пределах 0..255,
2. fileImage — массив байт, элементы которого имеют значение -128..127
Поэтому для подсчета байт будем использовать конструкцию
arrBytes[fileImage[i] & 0b11111111]++;

которая банально сбросит бит знака и вернет нам значение в диапазоне 0..255

И так, результаты:
46Мб файл 0.13 секунд (меньше секунды).
1Gb файл — 9 секунд.
Мы сделали это! Мы невероятно круты! Ускорились с 3 часов до 9 секунд.

Все, можно откинуться в кресле и попить чайку. А теперь еще один эксперимент —
попробуем файл в 32 Gb (например, HD фильм). Получим в результате треск
работающего HDD с вываливанием программы в Windows. КамАЗ вывалив кузов с песком сломал песочницу!

Что будем делать? Вспомним еще один факт. Файлы в ОС хранятся обычно порциями (кластерами) по 2-64Кб
(зависит от типа файловой системы, настроек и т.п.). Будем считывать порциями, для примера в 64000 байт.
Попытаемся разгрузить КамАЗ экскаватором достаточно большими порциями:

Используем буфер.
// Вариант 5. Считываем массив кусками.
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        long startTime = System.currentTimeMillis();
        
        int  bufferSize = 64000;
        byte buffer[]   = new byte[64000];

        while (inputStream.available() > 0) {
            if (inputStream.available() < 64000) bufferSize = inputStream.available();
            inputStream.read(buffer, 0, bufferSize );
            for (int i = 0; i <bufferSize ; i++) arrBytes[ buffer[i] & 0b11111111 ]++;
        }

		inputStream.close();
        // Выводим отсортированный по байт-коду в обратном порядке
        for (long i = 255; i >= 0 ; i--)
            if (arrBytes[(int) i] > 0) System.out.print(i + " ");

		long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}

В итоге получили:
46Мб файл 0.08 секунд (меньше секунды).
1Gb файл — 0.9 секунд(меньше секунды).
32Gb файл — 31 секунда.

Заметим для 1 Gb файла мы улучшили производительность с нескольких часов до долей секунд!!!

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

P.S. Кто-то скажет пример надуманный и т.п. Но полно похожих задач — проанализировать огромный объем элементов, имеющих конечное число состояний.
Например изображения (RGB — обычно хранятся в 24 байтах, в нашем случае long[] arrRGB = new long[256*256*256] занял бы в памяти всего 64Мб),
музыка (амплитуда обычно оцифровывается в 16 или 24 бита) или дискретные показатели датчиков и т.п.
  • ,

Выход из бесконечного цикла

Здравствуйте, дамы и господа!
Помогите, пожалуйста, решить проблему — необходимо выйти из бесконечного цикла с помощью нажатия клавиши (напр. ESC).

Вот мой код:

package likearobot;

import java.awt.Robot;
import java.awt.event.KeyEvent;

import java.awt.event.*;

public class LikeARobot {

    public static void main(String[] args) {
     KeyEvent e;
  Robot bot = null;
  try {
   bot = new Robot();
  } catch (Exception failed) {
   System.err.println("Failed instantiating Robot: " + failed);
  }
  int mask = InputEvent.BUTTON1_DOWN_MASK;

            

          //Открываем окно браузера
          bot.delay(1000);
          bot.mouseMove(140, 1190);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          
          
          bot.delay(2000);
          
          
          for ( ; ; )  
          {
           int picture = 300;
           int pictureTwo = 370;
          for (int i = 0; i < 2; i++)   
     
               {
         
          for (int j = 0; j < 12; j++)
          {
          //Открываем 1-ю картинку
          bot.mouseMove(picture, pictureTwo);
          picture = picture + 130;
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          
          
          bot.delay(2000);
          
          //Разворачиваем окно
          bot.mouseMove(1360, 309);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          
          
          bot.delay(2000);
          
          //Cтавим лайк
          bot.mouseMove(1130, 863);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          bot.delay(100);
          bot.mouseMove(1128, 815);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          bot.mouseMove(1168, 867);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          bot.mouseMove(1072, 867);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          bot.mouseMove(1128, 736);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);
          
          //Закрываем окно
          bot.delay(2000);
          bot.mouseMove(1895, 7);
          bot.mousePress(InputEvent.BUTTON1_MASK);
          bot.mouseRelease(InputEvent.BUTTON1_MASK);

          bot.delay(2000);
          }
          picture = 300;
          
          
          bot.delay(2000);
          bot.keyPress(KeyEvent.VK_F5);
          bot.delay(2000);
          
          }
          bot.delay(2000);
          bot.keyPress(KeyEvent.VK_F5);
          bot.delay(2000);
    
          
          }
          
          
          
          }
    



    }   
 
    


Я кажется нашел решение, но не смог его применить:

public void keyPressed(KeyEvent e) {}
 
    public void keyReleased(KeyEvent e) {
      if (e.getKeyChar() == KeyEvent.VK_ENTER) {
           System.exit(0);
      }
    }
 
    public void keyTyped(KeyEvent e) {}


Помогите, пожалуйста дополнить мой код, чтобы решить эту проблему.

Заранее всем спасибо!

Junior с 3 попыток

История моего обучения почти на 99% повторяет все ранее изложенные мемуары, постараюсь коротко.
Я учился в университете по специальности, которая подразумевает под собой IT-направление, но, увы, что касалось программирования, дальше «Hello World» дело не двигалось. Менялись языки, вместе с ними менялись преподаватели, а толку было мало.

Появлялись первые мысли: «А что же дальше?»

Началось все стандартно: товарищ показал ресурс с классными задачами и системой оценки этих задач, как вы уже догадались, это был тот самый JavaRush! Было это в 2014 году.
10 Уровней пролетели как секунда, нашлись деньги, появилась подписка. Следующие уровни шли тяжелее, так как затрагивали те области, по которым не ступал мой разум… Осилив n уровней после приобретения подписки уверенность подскочила до небес и толкнула меня создать резюме на небезызвестном сайте вакансий. В течение недели даже нашлась вакансия, под которую подпадали мои навыки программиста.
Первое собеседование прошло ужасно, и это, кстати, очень важный момент, в который нельзя опускать руки. Это собеседование дало мне пинок мотивации и следующие 2 месяца я занимался ежедневно по 6-8 часов. Но во мне таился страх завала следующего собеседования, и так и не дойдя до такового я потерял мотивацию, плюс добавились обстоятельства, которые забрали все свободное время, а подписка осталась пылиться…

Вторая попытка началась с того же вопроса: «А что же дальше?»

Тот, кто придумал фразу «повторение — мать учения» был чертовски прав! Вторая попытка шла в разы лучше первой, усвоенные знания хорошо закрепились и структурировались в сером веществе. Еще 2 или 3 месяца прошли в напряженном выкраивании времени для решения задач и чтения лекций, но подкралось одно очень суровое обстоятельство, имя которому — Диплом! Вторая попытка была похоронена вместе с первой, даже не добравшись до заветного собеседования…

Третья попытка началась с тревожного вопроса после защиты диплома: «И что теперь?»

Для третьей попытки требовалась новая тактика. Взяв пачку книг и видео курсов, я плотно уселся за занятия на ежедневной основе и уже через пару недель поднял все старые воспоминания даже подкрепив их новыми. Третья попытка дала мне возможность осмыслить почти каждый символ, литерал и строчку, используемые в коде. Через месяц после старта третьей попытки, я начал искать собеседования, но набор Junior'ов был очень скудный, а количество претендентов на одно место порой достигало 70 человек.

И наконец, в декабре 2015, после успешного выполнения тестового задания и прохождения собеседования в трудовой книжке появилась запись «младший программист». Сейчас заканчивается мой испытательный срок и вероятность трудоустройства на постоянной основе стремится к 100%.

Пожелания


Ребята, не стремитесь к космическому количеству решенных задач. Не решайте задачи для того, чтобы решить задачи! Вникайте в суть, задавайте вопросы, сомневайтесь. Смотрите шире. Да, JAVA очень нужна, но помимо JAVA нужно много знаний. Читайте про сети, web технологии, шаблоны проектирования и многое многое другое.

Традиционный список того, что нужно знать


  1. Основы
    Без основ никуда, если пару раз прочитать устройство HashMap, то скорее всего уже никогда не забудешь. В основы входят String, Collections API, Threads, I/O.Threads, I/O.
  2. Debug
    Обязательная вещь в больших Enterprise проектах.
  3. ООП
    Очень классно порешать тесты на QUIZFUL
  4. Servlets
    Так как Java — это всякого рода web и Enterprise, то с 50% сервлеты вам пригодятся.
  5. SQL
    Тут без комментариев.
  6. Spring и Hibernate
    Связка, которая мне сначала не пригодилась, но с которой постоянно приходится иметь дело, поэтому MUST HAVE!

P.S. Насчет работы. Верьте рассказам людей про то, что это лучшая работа в мире.
P.S.S. Спасибо JavaRush за интересные задачи, и огромное спасибо hubert
  • ,

Оформление кода

Одну из задач (которая была решена и принята сервером) я реализовал в виде кода (забил * и X-ми чтобы не спойлерить).

/* xxx
1. Считывать строки(параметры) с консоли, пока пользователь не введет пустую строку(Enter).
2. Каждый параметр соответствует имени ***.
Для каждого параметра:
3. Создать объект *** класса ***, который равен *** из getX(String параметр).
4. Вывести на экран toString().
*/

public class Solution
{
    public static void main(String[] args) throws Exception
    {
        //Add your code here
        List<String> al= new ArrayList<>();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String str;
        while(!"".equals(str = reader.readLine())) al.add(str);
        for (int i = 0; i <al.size(); i++) System.out.println(XFactory.getX(al.get(i)).toString());
    }
...

Зашедший в гости полузнакомый раскритиковал, что так не пишут (это тебе не C и т.п.).
Не подскажете в чем я не прав (есть какие нормы и общепринятые стандарты)?
Или использование в одной строчке нескольких конструкций (оно вообще, без промежуточных присваиваний временным переменным, может привести в каких-либо ситуациях к каким-либо возможным последствиям?) — дурной тон?
Основные переменные (al, reader, str) объявлены до их использования (pascal-стиль), так как мне удобнее, всегда знаешь где можешь найти описание переменной с возможным комментарием.
Вспомогательные переменные объявлены в нужной зоне видимости (как переменная цикла i).
Idea не ругается, правда предлагает 2 опции:
Split into declaration and assigment (таки разделить объявление и присваивание) и заключить некоторые участки в блок try.

Как бы Вы правильнее написали код?

Что не так?
Для такой задачи не стоит комментировать каждую строчку.

18 Уровень дается мне очень тяжко уже 2 задача а я решить не могу подскажите что не так

18 Уровень дается мне очень тяжко уже 2 задача а я решить не могу подскажите что не так

package com.javarush.test.level18.lesson10.home09;

/* Файлы и исключения
Читайте с консоли имена файлов
Если файла не существует (передано неправильное имя файла), то
перехватить исключение FileNotFoundException,
вывести в консоль переданное неправильное имя файла и
завершить работу программы.
Закрыть потоки. Не использовать try-with-resources
Не используйте System.exit();
*/

import java.io.*;

public class Solution
{
    public static void main(String[] args) throws IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        FileReader fileInputStream =null;
        try{
            while (true){
                fileInputStream = new FileReader(reader.readLine());
            }
        }catch (FileNotFoundException e){
            System.out.println("передано неправильное имя файла");
            fileInputStream.close();
            return;
        }
        finally
        {  reader.close();
        }


    }

    }

Ребят Я не понимаю что нужно этой задаче


package com.javarush.test.level18.lesson10.home08;

import java.io.*;
import java.util.*;
/* Нити и байты
Читайте с консоли имена файлов, пока не будет введено слово "exit"
Передайте имя файла в нить ReadThread
Нить ReadThread должна найти байт, который встречается в файле максимальное число раз, и добавить его в словарь resultMap,
где параметр String - это имя файла, параметр Integer - это искомый байт.
Закрыть потоки. Не использовать try-with-resources
*/

public class Solution {
    public static Map<String, Integer> resultMap = new HashMap<String, Integer>();

    public static void main(String[] args) throws IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true)
        {
            String s = reader.readLine();
            if (s.equals("exit") ){
                break;
            }else {
                ReadThread readThread = new ReadThread(s);
                readThread.start();

            }
        }
        reader.close();
    }

    public static class ReadThread extends Thread {
        String s;
        ArrayList<Integer> list = new ArrayList<Integer>();
        HashMap<Integer,Integer> hashMap = new HashMap<Integer, Integer>();
        public ReadThread(String fileName) throws IOException
        {
            //implement constructor body
            this.s = fileName;
        }
        // implement file reading here - реализуйте чтение из файла тут
        public void run(){
            try
            {
                FileInputStream fp = new FileInputStream(s);
                while (fp.available()>0){
                    int k = fp.read();
                    list.add(k);
                }
                int max = 0;
                for (int i = 0; i <list.size() ; i++)
                {
                    int count = 0;
                    for (int j = 0; j <list.size() ; j++)
                    {
                        if (list.get(i)==list.get(j)){
                            count = count+1;
                        }
                    }
                    hashMap.put(list.get(i),count
                    );
                    if (count>max){
                        max = count;
                    }
                }

                synchronized (this)
                {
                    for (Map.Entry<Integer, Integer> p : hashMap.entrySet())
                    {
                        if (max == p.getValue())
                        {
                            resultMap.put(s, p.getKey());
                        }
                    }
                }

                fp.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

}

Ребят Я не понимаю что нужно этой задаче


package com.javarush.test.level18.lesson10.home08;

import java.io.*;
import java.util.*;
/* Нити и байты
Читайте с консоли имена файлов, пока не будет введено слово "exit"
Передайте имя файла в нить ReadThread
Нить ReadThread должна найти байт, который встречается в файле максимальное число раз, и добавить его в словарь resultMap,
где параметр String - это имя файла, параметр Integer - это искомый байт.
Закрыть потоки. Не использовать try-with-resources
*/

public class Solution {
    public static Map<String, Integer> resultMap = new HashMap<String, Integer>();

    public static void main(String[] args) throws IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true)
        {
            String s = reader.readLine();
            if (s.equals("exit") ){
                break;
            }else {
                ReadThread readThread = new ReadThread(s);
                readThread.start();

            }
        }
        reader.close();
    }

    public static class ReadThread extends Thread {
        String s;
        ArrayList<Integer> list = new ArrayList<Integer>();
        HashMap<Integer,Integer> hashMap = new HashMap<Integer, Integer>();
        public ReadThread(String fileName) throws IOException
        {
            //implement constructor body
            this.s = fileName;
        }
        // implement file reading here - реализуйте чтение из файла тут
        public void run(){
            try
            {
                FileInputStream fp = new FileInputStream(s);
                while (fp.available()>0){
                    int k = fp.read();
                    list.add(k);
                }
                int max = 0;
                for (int i = 0; i <list.size() ; i++)
                {
                    int count = 0;
                    for (int j = 0; j <list.size() ; j++)
                    {
                        if (list.get(i)==list.get(j)){
                            count = count+1;
                        }
                    }
                    hashMap.put(list.get(i),count
                    );
                    if (count>max){
                        max = count;
                    }
                }

                synchronized (this)
                {
                    for (Map.Entry<Integer, Integer> p : hashMap.entrySet())
                    {
                        if (max == p.getValue())
                        {
                            resultMap.put(s, p.getKey());
                        }
                    }
                }

                fp.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }

}

  • ,

FindBugs помогает узнать Java лучше

Статические анализаторы кода любят за то, что они помогают найти ошибки, сделанные по невнимательности. Но гораздо интереснее то, что они помогают исправить ошибки, сделанные по незнанию. Даже если в официальной документации к языку всё написано, не факт, что все программисты это внимательно прочитали. И программистов можно понять: всю документацию читать замучаешься.

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

В этом посте я расскажу о некоторых тонкостях Java, о которых я узнал в результате использования статического анализатора FindBugs. Возможно, какие-то вещи окажутся неожиданными и для вас. Важно, что все примеры не умозрительны, а основаны на реальном коде.

Тернарный оператор ?:


Казалось бы, нет ничего проще тернарного оператора, но у него есть свои подводные камни. Я считал, что нет принципиальной разницы между конструкциями
Type var = condition ? valTrue : valFalse;

и
Type var;
if(condition)
  var = valTrue;
else
  var = valFalse;


Оказалось, что тут есть тонкость. Так как тернарный оператор может быть частью сложного выражения, его результатом должен быть конкретный тип, определённый на этапе компиляции. Поэтому, скажем, при истинном условии в if-форме компилятор приводит valTrue сразу к типу Type, а в форме тернарного оператора сперва приводит к общему типу valTrue и valFalse (несмотря на то, что valFalse не вычисляется), а затем уже результат приводит к типу Type. Правила приведения оказываются не совсем тривиальными, если в выражении участвуют примитивные типы и обёртки над ними (Integer, Double и т. д.) Все правила подробно описаны в JLS 15.25. Посмотрим на некоторые примеры.

Number n = flag ? new Integer(1) : new Double(2.0);

Что будет в n, если flag установлен? Объект Double со значением 1.0. Компилятору смешны наши неуклюжие попытки создать объект. Так как второй и третий аргумент — обёртки над разными примитивными типами, компилятор разворачивает их и приводит к более точному типу (в данном случае double). А уже после выполнения тернарного оператора для присваивания снова выполняется боксинг. По сути код эквивалентен такому:
Number n;
if( flag )
    n = Double.valueOf((double) ( new Integer(1).intValue() ));
else
    n = Double.valueOf(new Double(2.0).doubleValue());


С точки зрения компилятора код не содержит проблем и прекрасно компилируется. Но FindBugs выдаёт предупреждение:

BX_UNBOXED_AND_COERCED_FOR_TERNARY_OPERATOR: Primitive value is unboxed and coerced for ternary operator in TestTernary.main(String[])

A wrapped primitive value is unboxed and converted to another primitive type as part of the evaluation of a conditional ternary operator (the b? e1: e2 operator). The semantics of Java mandate that if e1 and e2 are wrapped numeric values, the values are unboxed and converted/coerced to their common type (e.g, if e1 is of type Integer and e2 is of type Float, then e1 is unboxed, converted to a floating point value, and boxed. See JLS Section 15.25.
Разумеется, FindBugs предупреждает и о том, что Integer.valueOf(1) эффективнее, чем new Integer(1), но это уж все и так знают.

Или такой пример:
Integer n = flag ? 1 : null;


Автор хочет поместить null в n, если флаг не установлен. Думаете, сработает? Да. Но давайте усложним:
Integer n = flag1 ? 1 : flag2 ? 2 : null;


Казалось бы, особой разницы нет. Однако теперь, если оба флага сброшены, данная строчка генерирует NullPointerException. Варианты для правого тернарного оператора — int и null, поэтому результирующий тип Integer. Варианты для левого — int и Integer, поэтому по правилам Java результат — int. Для этого надо совершить unboxing, вызвав intValue, что и выдаёт исключение. Код эквивалентен такому:
Integer n;
if( flag1 )
    n = Integer.valueOf(1);
else {
    if( flag2 )
        n = Integer.valueOf(Integer.valueOf(2).intValue());
    else
        n = Integer.valueOf(((Integer)null).intValue());
}


Здесь FindBugs выдаёт два сообщения, которых достаточно, чтобы заподозрить ошибку:
BX_UNBOXING_IMMEDIATELY_REBOXED: Boxed value is unboxed and then immediately reboxed in TestTernary.main(String[])
NP_NULL_ON_SOME_PATH: Possible null pointer dereference of null in TestTernary.main(String[])
There is a branch of statement that, if executed, guarantees that a null value will be dereferenced, which would generate a NullPointerException when the code is executed.

Ну и последний пример на эту тему:
double[] vals = new double[] {1.0, 2.0, 3.0};
double getVal(int idx) {
    return (idx < 0 || idx >= vals.length) ? null : vals[idx];
}


Неудивительно, что этот код не работает: как функция, возвращающая примитивный тип, может вернуть null? Удивительно, что он без проблем компилируется. Ну почему компилируется — вы уже поняли.

DateFormat


Для форматирования даты и времени в Java рекомендуется пользоваться классами, реализующими интерфейс DateFormat. Например, это выглядит так:
public String getDate() {
    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}


Зачастую класс многократно использует один и тот же формат. Многим придёт в голову идея оптимизации: зачем каждый раз создавать объект формата, когда можно пользоваться общим экземпляром?
private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

public String getDate() {
    return format.format(new Date());
}


Вот так красиво и здорово, только, к сожалению, не работает. Точнее работает, но изредка ломается. Дело в том, что в документации к DateFormat написано:
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

И это действительно так, если посмотреть внутреннюю реализацию SimpleDateFormat. В процессе выполнения метода format() объект пишет в поля класса, поэтому одновременное использование SimpleDateFormat из двух потоков приведёт с некоторой вероятностью к неправильному результату. Вот что пишет FindBugs по этому поводу:
STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE: Call to method of static java.text.DateFormat in TestDate.getDate()
As the JavaDoc states, DateFormats are inherently unsafe for multithreaded use. The detector has found a call to an instance of DateFormat that has been obtained via a static field. This looks suspicous.

For more information on this see Sun Bug #6231579 and Sun Bug #6178997.

Подводные камни BigDecimal


Узнав, что класс BigDecimal позволяет хранить дробные числа произвольной точности, и увидев, что у него есть конструктор от double, некоторые решат, что всё ясно и можно делать так:
System.out.println(new BigDecimal(1.1));

Делать так действительно никто не запрещает, вот только результат может показаться неожиданным: 1.100000000000000088817841970012523233890533447265625. Так происходит, потому что примитивный double хранится в формате IEEE754, в котором невозможно представить 1.1 идеально точно (в двоичной системе счисления получается бесконечная периодическая дробь). Поэтому там хранится максимально близкое значение к 1.1. А конструктор BigDecimal(double) напротив работает точно: он идеально преобразует заданное число в IEEE754 к десятичному виду (конечная двоичная дробь всегда представима в виде конечной десятичной). Если же хочется представить в виде BigDecimal именно 1.1, то можно написать либо new BigDecimal(«1.1»), либо BigDecimal.valueOf(1.1). Если число не выводить сразу, а поделать с ним какие-то операции, можно и не понять, откуда берётся ошибка. FindBugs выдаёт предупреждение DMI_BIGDECIMAL_CONSTRUCTED_FROM_DOUBLE, в котором даются те же советы.

А вот ещё одна штука:
BigDecimal d1 = new BigDecimal("1.1");
BigDecimal d2 = new BigDecimal("1.10");
System.out.println(d1.equals(d2));


Фактически d1 и d2 представляют собой одно и то же число, но equals выдаёт false, потому что он сравнивает не только значение чисел, но и текущий порядок (число знаков после запятой). Это написано в документации, но мало кто будет читать документацию к такому знакомому методу как equals. Такая проблема может всплыть далеко не сразу. Сам FindBugs об этом, к сожалению, не предупреждает, но есть популярное расширение к нему — fb-contrib, в котором данный баг учтён:

MDM_BIGDECIMAL_EQUALS

equals() being called to compare two java.math.BigDecimal numbers. This is normally a mistake, as two BigDecimal objects are only equal if they are equal in both value and scale, so that 2.0 is not equal to 2.00. To compare BigDecimal objects for mathematical equality, use compareTo() instead.

Переводы строк и printf


Нередко программисты, перешедшие на Java после Си, с радостью открывают для себя PrintStream.printf (а также PrintWriter.printf и т. д.). Мол, отлично, это я знаю, прямо как в Си, ничего нового учить не надо. На самом деле есть отличия. Одно из них кроется в переводах строк.

В языке Си есть разделение на текстовые и бинарные потоки. Вывод символа '\n' в текстовый поток любым способом автоматически будет преобразован в системно-зависимый перевод строки ("\r\n" на Windows). В Java такого разделения нет: надо передавать в выходной поток правильную последовательность символов. Это автоматически делают, например, методы семейства PrintStream.println. Но при использовании printf передача '\n' в строке формата — это просто '\n', а не системно-зависимый перевод строки. К примеру, напишем такой код:
System.out.printf("%s\n", "str#1");
System.out.println("str#2");


Перенаправив результат в файл, увидим:


Таким образом можно получить странную комбинацию переводов строки в одном потоке, что выглядит неаккуратно и может снести крышу какому-нибудь парсеру. Ошибку можно долго не замечать, особенно если вы преимущественно работаете на Unix-системах. Для того, чтобы вставить правильный перевод строки с помощью printf, используется специальный символ форматирования "%n". Вот что пишет FindBugs по этому поводу:

VA_FORMAT_STRING_USES_NEWLINE: Format string should use %n rather than \n in TestNewline.main(String[])

This format string include a newline character (\n). In format strings, it is generally preferable better to use %n, which will produce the platform-specific line separator.


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

Ссылка на первоисточник: https://sohabr.net/post/201334/

Вакансии, трудоустройство джунов в Москве

Всем привет! Предлагаю тем, кто уже трудоустроился в Москве программистом помогать устраиваться на работу студентам JR.

Варианты помощи:
1. Опубликовать здесь в каких компаниях(департаментах) сейчас есть спрос на джунов.
2. Если есть спрос на джунов — то какой стек технологий требуется, например: Java, Spring, Spring security, GWT, HTML, CSS, SQL, Hibernate, Maven, GIT, JS. Включить в список средство разработки (IDE). Обобщить что дополнительно требуют на собеседовании: портфолио, сертификаты, решение логических задач. Думаю, что все должны требовать решать задачи по Java core, SQL по-умолчанию.
3. Опубликовать здесь открытые проекты Java, где могут поучаствовать джуны. Учить нас там явно никто не будет, но можно попробовать разобраться самому, поучаствовать в реальном проекте.

Лично я не смог трудоустроиться в Москве в январе этого года, следующая попытка — в январе 2016. Работные агрегаторы не сильно помогают. Часто вакансии джунов вообще не публикуют или забивают отвечать на отклики. Особенно у «госников» и лютых «корпоратов».

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

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

Лайфхак из моего опыта — джунов берут на вакансии с опытом работы от 1 года. На собеседованиии надо показать хорошее знание теории и лютое желание работать.

Работа с базой данных и многопоточность

Здравствуйте, недавно начал писать сервер для работы с базой данных. Возник такой вопрос: сервер получается многопоточный, то есть для каждого клиента будет создаваться свой поток. Хотел бы узнать как реализовать подключение к базе данных. Есть класс java.sql.Сonnection, так вот для каждого отдельного клиента его нужно инициализировать отдельно или можно как то безопасно его использовать в разных потоках? Также слышал что есть connection pool в каких случаях и как его нужно использовать?