SOS !Встречаемость символов! 8 уровень, 11 лекция

Решил эту задачу, проверил, все работает, но валидатор отправил меня в далекое плаванье с моим решением. Подскажите, пожалуйста, что не так, а то у меня уже третий день горит.
Вот код:
public class Solution {
public static void main(String[] args) throws Exception{
TreeMap<Integer, Integer> map = new TreeMap<>();
BufferedReader reader = new BufferedReader(new FileReader(args[0]));
while (reader.ready()) {
char[] array = reader.readLine().toCharArray();
for (char letter: array) {
if(map.get((int)letter) == null)
map.put((int)letter, 1);
else {
int a = map.get((int)letter);
a++;
map.put((int)letter, a);
}
}
}
reader.close();
char a;
int i;
for (Map.Entry<Integer, Integer> pair: map.entrySet()) {
i = pair.getKey();
a = (char) i;
System.out.println( a + " " + pair.getValue());
}
reader.close();
}
}
Говорит, мол, вывод должен быть отсортирован по возрастанию кода ASCII. Но он и так отсортирован, в этом и суть!
  • ,

Помогите! Не удается получить доступ к сайту!

Здравствуйте! Со вчерашнего дня сражаюсь с такой проблемой:

Не удается получить доступ к сайту

Веб-страница по адресу javarush.ru/course.html, возможно, временно недоступна или постоянно перемещена по новому адресу.
ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY

Не один браузер не открывает сайт.Очистка Куки, кэша DNS через командную строку, проверка на вирусы, замена Hosts, изменение адреса dns на 8.8.8.8, вход с ip других стран не помог. С мобильного нет проблем со входом на сайт.
  • ,

Где взять задачи(идеи) для закрепления материала по пройденым темам JR?

Здравсвуйте. Сейчас на 17-м уровне, и ощущается, что тяжело уже все идет, мотивация падает из-за того, что не понимаешь что-то или даже больше из-за того, что каша в голове.
Суть моего вопроса в общем в том, чтобы хотелось еще больше практики, мини проекты какие-то, но не тупо отсортировать коллекцию определенным образом, а чтобы была задумка какая-то интересная(например мини игра, парсер с сайта) но графику еще не изучал, поэтому только консоль. Может кто подсказать подобные интересные задачи?

Поздравление с Новым годом от Зеленой лягушки

Уважаемые джаварашевцы и джаварашатессы!

Веселье весельем, а серьезное пожелание будет как никогда кстати. Желаю здоровья, взвешенных решений, крепких отношений. И учиться, учиться и еще раз учиться. В мое детство над этой фразой Владимира Ильича Ленина все смеялись. А я, будучи веселым беззаботным школьником, особенно. Но вот прошло несколько десятков лет, настал XXI век. И оглядываясь вокруг, а особенно бросая взгляд в будущее, я уже не смеюсь. Постоянная учеба стала актуальной тенденцией и вскоре станет насущной необходимостью. Без этого человек не сможет занять достойного места в обществе. Пожизненных вам способностей и возможностей к обучению!

С Новым годом!



С уважением,
Зеленая лягушка.
  • ,

Год спустя, Android

Парни, привет! Хочу рассказать, как прошел первый год работы программистом, где я нахожусь сейчас, через что прошел и что маячит на горизонте.

Итак, со времени написания первой статьи у меня сменился работодатель. Сейчас я работаю в Альфа-банке: не в лабе, а над внутренним проектом (для сотрудников банка). У нас своя продуктовая команда, всего 7 человек, детали могу рассказывать очень выборочно, так как NDA.

Я один Android-разработчик. Мы работаем двухнедельными спринтами, то есть ставим конкретные задачи на 2 недели вперед и следим за их выполнением. Наш продакт-менеджер решает, куда нам нужно развиваться и какой функционал реализовать. Мы, разработчики, берем день на оценку задачи (нужно понять, какие трудности на iOS, Android, в дизайне и на сервере) и даем свою оценку, мол, реально сделать за такое-то количество дней. Продакт оценивает, стоит ли игра свеч, и мы либо повторяем процедуру либо приступаем к реализации.

У меня нет макбука, но может появится в январе. В банке много бюрократии (на все нужны заявки, на интернет, на флешку, на youtube) и это тяжело. Но сильная корпоративная культура, много интересных и приятных людей в компании. Есть терки между отделами. Приятный ДМС, прикольный офис на м. Технопарк. Конечно, зарплата интересна, да?) Зарплата у меня обычная для мидла в Москве.

Что было позади? В мае я ушел из студии. Мне предложили расстаться полюбовно: у них было ко мне претензии, я уже вел переговоры с QIWI о работе, у меня были сложные отношения с тимлидом — в общем, правда стоило уйти. Еще мне платили мало, и, херовый я работник, сильно стараться меня это не мотивировало.
После маленькой студии, которая уже десяток лет бьется за небольшой кусок хлеба и не может наладить внутренние процессы, попасть в Альфу было раем.

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

В общем, проработав в студии 5 месяцев, я толком ничему не научился. У меня тогда шли переговоры с QIWI (длительное оформление, но они просто слились после прохождения мною всех этапов собеседования — четырех, карл!- будьте с ними аккуратнее), и я понимал, что нужно что-то делать. Я с помощью знакомых вышел на тимлида в одной крутой московской IT компании. Договорился о собеседовании, которое не прошел, но ему понравился и мы договорились, что я буду с ним заниматься английским, а он подтянет меня в андроиде.

Мы с ним занимались три месяца, два раза в неделю часа по 1-1,5 часа на предмет. Он обычно рассказывал мне какую-то тему, концептуальную, а на задание давал читать исходники, подробные статьи на тему и практические задания, например, освоить библиотеки типа Dagger, RxJava, переопределить работу нативных классов Android и т.п. И это дало реальный скачок моим знаниям. Особенно клево было то, что был человек, которому я мог задавать вопросы.

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

Итак, что в перспективах? Мне все еще нужно освоить стек модных технологий. Реактивное программирование и Kotlin самые большие вершины из ближайшего. Я стал немного ориентироваться в архитектуре приложений, но пока сижу на обычном MVP, силюсь понять Clean архитектуру, но одному тут тяжело. Поэтому хочу перейти в чисто IT-шную компанию и прокачиваться в команде. С другой стороны, у меня хорошие условия здесь и еще поле непаханое в плане саморазвития — есть тысяча вещей, которые я могу сам освоить и отработать в своем проекте. Посмотрим, как карта ляжет.

Вот, спустя год работы разработчиком, я уже с интересом читаю Философию JAVA. Как человеку, не имеющему профильного образования, но имеющего высшее, это помогает посмотреть на программирование академически. Я нашел несколько youtube-каналов об android, которые мне нравятся, и смотрю записи с англоязычных конференций. Надо бы ходить на наши, но я предпочитаю гонять в Зельду и Splatoon 2 по вечерам :D

Хочется этот год как-то обобщить. Я, наверно, мямля и слабак, но честно сказать — год был пи*** какой тяжелый. Особенно первая работа в маленькой и хромой фирме. Условия отстой, коллектив не очень, а вам нужно как-то начинать. И еще дикий стресс из-за новых знаний, большей демпинг по зарплате. Если у вас есть семья, поверьте, вашему партнеру может быть не легко.

Но это стоит того. Правда, работать в IT, имея склонность к программированию, если и не счастье, но что-то очень близкое к этому. Есть свои минусы — вы много сидите, постоянный стресс изучения чего-то нового, вы БУДЕТЕ перерабатывать. Но то удовольствие, которое может приносить эта работа — мечта для многих профессий. Вы можете делать что-то полезное для людей, постоянно учиться и работать с новыми инструментами, вы в каком-то плане в арьергарде современной культуры, для вас создаются отличные условия труда, ваша профессия не привязана к вашему родному языку, а место работы — к производству,- в общем, отлично быть программистом сейчас.

Объективно, моя жизнь стала намного лучше, после решения сменить профессию. Мне иногда жалко думать, что я не сделал этого раньше и страшно думать, как бы я тратил свою жизнь впустую, если бы продолжил жить как раньше, как удобно, как известно. Но нынешние горизонты пьянят, профессиональное коммьюнити программистов отличное (англоязычное), а работа доставляет удовольствие каждый день.
Дерзайте, парни! Не думайте, что будет легко в первое время, но вам нужен где-то год опыта, чтобы вы стали привлекательным для работодателей. Мне даже из Яндекса звонили (правда, я провалил даже вводные три вопроса по телефону, но не это важно). В общем, желаю всем реализовать свои амбиции в новом году! С наступающим!

Загадка сериализации

Есть код:


package app;

import java.io.*;

public class Solution {
    public static void main(String[] args) throws Exception{
        B b1 = new B();
        File file = new File("D:\\test.txt");
        OutputStream os = new FileOutputStream(file);
        ObjectOutputStream oos = new ObjectOutputStream(os);
        oos.writeObject(b1);
        oos.close();
        os.close();

        InputStream is = new FileInputStream(file);
        ObjectInputStream ois = new ObjectInputStream(is);

        System.out.println("Before serialization: " + b1.str);
        b1 = (B) ois.readObject();
        System.out.println("After de-serialization: " + b1.str);
        ois.close();
        os.close();
    }
}
class A{
    protected String str = "A";
}
class B extends A implements Serializable{
    public B() {
        this.str += "B";
    }
}


Вывод в консоль:

Before serialization: AB
After de-serialization: A


Мат.часть по ссылке www.skipy.ru/technics/serialization.html говорит следующее:
При использовании Serializable десериализация происходит так: под объект выделяется память, после чего его поля заполняются значениями из потока. Конструктор объекта при этом не вызывается.

и следующее:
То есть при десериализации вызывается конструктор без параметров родительского НЕсериализуемого класса. Конструктор же дочернего объекта, того, который мы десериализуем, не вызывается.

Если смотреть код, то логика такова:
1. Сериализуем объект b1 класса B.
2. К моменту его сериализации b1.str = «AB», соответственно в выходной поток пишется именно это состояние объекта.
3. При десериализации (если следовать теории) должно происходить следующее:
— Под объект b1 выделяется память
— Вызывается конструктор без параметров родительского класса. При этом, как я предполагаю, поля объекта b1 инициализируются либо значениями, определенными в классе-родителе, либо значениями по умолчанию. Видимо так и происходит, поэтому b1.str становится = «А»
— И вот тут по теории поля b1 уже должны заполнятся реальными значениями из потока, т.е. b1.str должно стать = «AB».

Почему этого не происходит?

Вопрос по применению регулярных выражений

Добрый день, джаварашевцы и джаварашатессы!
Прошу подсказать следующее, есть код:


Pattern p = Pattern.compile("[a-z]+");
Matcher m = p.matcher("A mutable sequence of characters.");
int numberOfChar = m.groupCount();
System.out.println(numberOfChar);


В консоль должно быть выведено количество символов от a до z (c учетом повторения) в указанной строке. Выводит ноль. Никак не пойму почему. Уже несколько статей прочитал по регулярным выражениям. Не помогает. Почитал документацию Oracle по классам Pattern, Matcher. Опять не помогло. Наверное глаз замылился, не вижу чего-то очевидного.
Прошу бескорыстно помочь. И достичь цели — пройти 18 и 19 уровни до конца 2017 года.

С уважением,
Зеленая лягушка.
  • ,

Из системного администратора в Java Developer-а

Всем привет.
Меня зовут Евгений, мне 27 лет, есть ребенок и второй на подходе. Живу большую часть времени в городе Екатеринбург.
Я имею образования инженера путей сообщения, работал системных администратором несколько лет после окончания ВУЗа.

Сегодня последний днем моего испытательного срока, хотя еще две недели назад мой teamleader сказал, что можешь не париться, ты остаешься.
Что я имею на сегодняшний день:
1. Работа в международной компании (все без исключений заказчики с запада в основном Шведция, Норвегия). Компания bodyshop.
2, Возможность ротации, customer-ов много, проекты разные, каждый может выбрать себе по душе
2. Приходящие носители языка дважды в неделю
3, Ежегодный выезд на заграничный корпоратив
4. Хорошая кухня, много плюшек
5. Замечательный коллектив, количество умных людей на 1 кв.м просто фантастическое

Но давайте вернемся немного назад, еще полтора года назад ничего и близко похожего у меня не было. Работал в государственной компании сисадмином, получал среднюю по больнице зарплату, английский знал посредственно, и в общем надежды, что жизнь начнет становиться лучше не было.
Случайно в соц. сетях наткнулся на сайт JavaRush.ru, один знакомый описывал, как прикольный способ стать программистом и, что он прошел за пару дней уже 5 уровней. Решил попробовать, т.к. еще в школе увлекался и даже хотел поступать в тогда еще УрГУ на мат.мех, но сбился с пути истинного. В общем чем я собственно хуже?

Дело за малым, не спеша за месяц прошел 10 уровней, и тут акция как раз на скидку в 50%, купил годовую подписку. Через месяц бросил работу админом и уехал зимовать в семьей в Таиланд, с мыслью, что буду учиться каждый день и ничего меня не остановит, к этому моменту усиленно учил английский, возможно тема для другой статьи, но мне больше всего помогли стартануть подкасты на английском языке начинал с VOA, а потом по нарастающей с приходом понимания увеличивал сложность. Если кому то интересно более подробно, спрашивайте в комментах.

План я свой начал реализовывать сразу как только мы приехали в город Ао Нанг провинции Краби и нашли себе домик на сезон. Могу сказать одно, нужно заниматься регулярно и все получиться, у меня было примерно 8-12 часов работы 5 дней в неделю, куда входили как написания кода так и занятия английским языком. Могу сказать одно даже в новый год я начал работать 2го января. Ни каких поблажек себе не давал, хотя конечно были моменты когда падает мотивация и хочется все бросить, очень помогали истории успеха тут на сайте, дал себе слово тогда, что обязательно напишу свою, может быть кому то она поможет в трудную минуту найти в себе силы и победить валидатор (ресторан и архиватор, привет) + 20-ти летний опыт занятий спортом тут очень помог, делал все по расписанию.
В выходные с женой и дочкой путешествовали на мотоцикле по ближайшим провинциям Таиланда, наслаждались природой и погодой. Отдыхал по максимуму, это тоже часть работы, хотя иногда в выходные садился за код или книжку по Java, когда уж прям совсем невтерпеж, но старался придерживаться режима.

Примерно после нового года я был уровне на 25-30, решил тогда, что все я крутой программист(на самом деле нет), пора устраиваться работать, сделал резюме на hh, посыпались заявки, опять же описывать как я писал его не буду, но делал его пару недель, и потом регулярно дополнял, потом еще перевел на английский, оформил все в лучшем виде, хоть и опыта не было в программировании, но оно явно приглянулось hr-ам, действительно довольно часто писали. Естественно первый несколько собеседований вернули меня на землю, понял как много я еще не знаю и то, что знаю, нужно было конкретно структурировать, чем я и занялся.

После этого встал выбор куда идти Android или JavaEE попробовал первое, прошел книжку HeadFirst и в целом примерно 30 мелких проектов написал, но тут пользуясь одним из сайтов по изучению английского увидел, как круто у них сделана верстка под мобильные и как хреново работает мобильное приложение. Призадумался и принял решение учить JavaEE, забегая в перед могу сказать, что идею учить Android не бросил и сейчас в планах освоить его. Тем не менее на тот момент отказался от идеи android. Долго ли коротко, начал учить сопутствующие технологии которые обязательны sql/maven/git/spring/hibernate и наверно отдельно выделю rest архитектуру, про нее часто спрашивают и вообще первые же два моих проекта которые ушли в production, это rest api.
Все это нужно знать, все это спрашивают, но знать можно поверхностно, написать 10-ок другой мелких проектов используя их, к примеру задание на стажировку реально пишется за пол дня, день, без фронта, он нафиг на Java не нужен, можно немного поучить JS/React/Node, если есть желание идти на фронт, но можно вообще только их учить и вообще не учить Java, там работы и заказчиков много больше, но там своя специфика.

В общем, примерно мае я вернулся в Россию, потому что были тут дела и решил, что пора устраиваться в офис, до этого все собеседования проходил по Skype (офер не получил ни разу на тот момент).
Приехал начал переодически ходить по собеседованиям, мне это очень не нравится ибо забирает очень много моральных и физических сил, и сильно мешает процессу учебы и написанию кода в целом(Skype помогает), поэтому ходил пару раз в неделю, где то нужны были более опытные люди, где то мне не понравилось, но в итоге прошел очередное собеседование по Skype, меня хотели отправить сразу же работать onsite в Швецию, естественно опыта моего не достаточно было, но я понравился teamleader-у и он меня посоветовал на внутренний проект, после чего я прошел еще одно собеседование уже в офисе у нас в Екатеринбурге, где задали пару вопросов и парочку на английском, после чего сказали, английский твой цитирую: «бывает и хуже», что конечно задело эго, но опять же дало пинок учить дальше, отпустили «погулять» и через 10 минут сделал мне офер, я на тот момент ожидал сильно меньший. Офер я естественно принял.

Хочу отдельно остановиться на первых месяцах работы, почему то мало кто про них пишет, но для меня они были настоящим кошмаром, я думал меня уволят честно говоря. Было адски сложно, дали задачу сразу же писать свой проект, вернее часть проекта один micro service, но для меня он был скорее огромным монстром, потому что мне нужно было продумывать все начиная от архитектуры и используемых фреймворков до exception handling. Сильно нервничал и думал, что от меня ждут, что это все сделаю за пару недель, что очень мешало сосредоточится на задаче и принимать верные решения. В итоге огромная благодарность моему тимлиду, он много помогал мне, объяснил многие базовые вещи и вообще ни как на меня не давил.

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

Простите за длинный текст, и спасибо всем кто дочитал до конца.

ps: думаю по мере опыта, буду дополнять статью мелкими заметками, если кому то будет интересна эта моя писанина
  • ,

Менторство

Решил попробовать себя в наставничестве. Безвозмездно. Ориентируюсь на людей где-то с 20-го уровня, которые начинают делать веб-приложение.
Варианты взаимодействия.
-Можете задавать вопросы.
-Ревью кода какого-нибудь pet project'a.
-Можно выбрать тему и я по ней что-нибудь расскажу/дам ссылки/может, придумаю какое-нибудь задание, которое потом, может, посмотрю.
В нескольких словах о себе: закончил JavaRush, 1.5 года работаю Java-разработчиком.
Если кого-то заинтересует — добавляйтесь лучше сюда

Что такое дедлок

Перевод грамотного объяснения примера из javadocs со Stackoverflow

public class Deadlock {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
        public synchronized void bow(Friend bower) {
            System.out.format("%s: %s" + "  has bowed to me!%n", this.name, bower.getName());
            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s"
                + " has bowed back to me!%n",
                this.name, bower.getName());            
        }
    }

    public static void main(String[] args) {
        final Friend alphonse =
            new Friend("Alphonse");
        final Friend gaston =
            new Friend("Gaston");
        new Thread(new Runnable() {
            @Override
            public void run() { 
               // System.out.println("Thread 1");
                alphonse.bow(gaston); 
               // System.out.println("Th: gaston bowed to alphonse");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() { 
              //  System.out.println("Thread 2");
                gaston.bow(alphonse);
              //  System.out.println("2.gaston waiting alph bowed");
            }
        }).start();
    }
}


Здесь нужно понять две важные вещи:
1) Что делает каждая из одновременно выполняющихся нитей?
2) Какие локи используются?

Начнем с конца. Вы создали два объекта класса Friend: alphonse и gaston. У каждого из них есть свой лок. Так что локов два: альфонсов и гастонов. При входе в синхронизированный метод объекта, лок этого объекта запирается, и освобождается — отпирается — когда из метода выходят.

Теперь о нитях. Первая, назовем ее нить Alphonse (с большой буквы, чтобы отличить от объекта alphonse) делает следующее (A — обозначает Alphonse)

A: alphonse.bow(gaston) — получает лок alphonse
A: gaston.bowBack(alphonse) — получает лок gaston
A: возвращается из обоих методов, тем самым освобождая лок

В это самое время нить Gaston…

G: gaston.bow(alphonse) — получает лок gaston
G: alphonse.bowBack(gaston) — получает лок alphonse
G: возвращается из обоих методов, тем самым освобождая лок

Теперь сведем эти данные вместе и получим ответ. Нити могут переплетаться (т. е. их события совершаться) в разных порядках. Дедлок, к примеру, получится, если опрядок будет таким:

A: alphonse.bow(gaston) — получает лок alphonse
G: gaston.bow(alphonse) — получает лок gaston
G: пытается вызвать alphonse.bowBack(gaston), но блокируется, ожидая лока alphonse
A: пытается вызвать gaston.bowBack(alphonse), но блокируется, ожидая лока gaston

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

Впрочем, возможно и другое переплетение, в котором одна из нитей успеет завершиться до начала второй:

A: alphonse.bow(gaston) — получает лок alphonse
A: gaston.bowBack(alphonse) — получает лок gaston
A: возвращается из обоих методов, открывая оба лока
G: gaston.bow(alphonse) — получает лок gaston
G: alphonse.bowBack(gaston) — получает лок alphonse
G: возвращается из обоих методов, открывая оба лока

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

Когда результат зависит от порядка одновременно происходящих событий (запланированного порядка или скорости выполнения), это называется «race condition» — «состоянием гонки». Не все race condition потенциально производят дедлок, однако, по моему опыту, дедлоки происходят только в race condition.

level39.lesson09.big01 Задание 1

Помогите понять, что не нравится валидатору. Спасибо!

Задание 1

Сегодня мы напишем парсер логов.
Лог файл имеет следующий формат:
ip username date event status
Где:
ip — ip адрес с которого пользователь произвел событие.
user — имя пользователя (одно или несколько слов разделенные пробелами).
date — дата события в формате day.month.year hour:minute:second
event — одно из событий:
LOGIN — пользователь залогинился,
DOWNLOAD_PLUGIN — пользователь скачал плагин,
WRITE_MESSAGE — пользователь отправил сообщение,
SOLVE_TASK — пользователь попытался решить задачу,
DONE_TASK — пользователь решил задачу.
Для событий SOLVE_TASK и DONE_TASK существует дополнительный параметр,
который указывается через пробел, это номер задачи.
status — статус:
OK — событие выполнилось успешно,
FAILED — событие не выполнилось,
ERROR — произошла ошибка.
Пример строки из лог файла:
«146.34.15.5 Eduard Petrovich Morozko 05.01.2021 20:22:55 DONE_TASK 48 FAILED».
Записи внутри лог файла не обязательно упорядочены по дате, события могли
произойти и быть записаны в лог в разной последовательности.

Класс, который будет отвечать за парсинг логов называется LogParser.
1.1. Добавь в класс LogParser конструктор с парметром Path logDir, где logDir — директория с логами (логов может быть несколько, все они должны иметь расширение log).
1.2. Реализуй интерфейс IPQuery у класса LogParser:
1.2.1. Метод getNumberOfUniqueIPs(Date after, Date before) должен возвращать
количество уникальных IP адресов за выбранный период. Здесь и далее,
если в методе есть параметры Date after и Date before, то нужно возвратить
данные касающиеся только данного периода (включая даты after и before).
Если параметр after равен null, то нужно обработать все записи, у которых
дата меньше или равна before.
Если параметр before равен null, то нужно обработать все записи, у которых
дата больше или равна after.
Если и after, и before равны null, то нужно обработать абсолютно все записи
(без фильтрации по дате).
1.2.2. Метод getUniqueIPs() должен возвращать множество, содержащее все
неповторяющиеся IP. Тип в котором будем хранить IP будет String.
1.2.3. Метод getIPsForUser() должен возвращать IP, с которых работал
переданный пользователь.
1.2.4. Метод getIPsForEvent() должен возвращать IP, с которых было произведено
переданное событие.
1.2.5. Метод getIPsForStatus() должен возвращать IP, события с которых
закончилось переданным статусом.

Реализацию метода main() можешь менять по своему усмотрению.

package com.javarush.test.level39.lesson09.big01;

import com.javarush.test.level39.lesson09.big01.query.IPQuery;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class LogParser implements IPQuery
{
    private Path logDir;

    public LogParser(Path logDir)
    {
        this.logDir = logDir;
    }

    @Override
    public int getNumberOfUniqueIPs(Date after, Date before)
    {
        return getUniqueIPs(after, before).size();
    }

    @Override
    public Set<String> getUniqueIPs(Date after, Date before)
    {
        Set<String> resultSet = new HashSet<>();
        List<String> list = getLinesBetweenDates(after, before);
        for (String str : list)
            resultSet.add(str.split("\\t")[0]);
        return resultSet;
    }

    @Override
    public Set<String> getIPsForUser(String user, Date after, Date before)
    {
        Set<String> resultSet = new HashSet<>();
        List<String> list = getLinesBetweenDates(after, before);
        for (String str : list)
        {
            String[] values = str.split("\\t");
            String userFromFile = values[1];
            if (userFromFile.equals(user))
                resultSet.add(values[0]);
        }
        return resultSet;
    }

    @Override
    public Set<String> getIPsForEvent(Event event, Date after, Date before)
    {
        Set<String> resultSet = new HashSet<>();
        List<String> list = getLinesBetweenDates(after, before);
        for (String str : list)
        {
            String[] values = str.split("\\t");
            String eventFromFile;
            if (values[3].contains(" "))
                eventFromFile = values[3].split(" ")[0];
            else eventFromFile = values[3];
            if (Event.valueOf(eventFromFile).equals(event))
                resultSet.add(values[0]);
        }
        return resultSet;
    }

    @Override
    public Set<String> getIPsForStatus(Status status, Date after, Date before)
    {
        Set<String> resultSet = new HashSet<>();
        List<String> list = getLinesBetweenDates(after, before);
        for (String str : list)
        {
            str = str.trim();
            String[] values = str.split("\\t");
            if (Status.valueOf(values[values.length - 1]).equals(status))
                resultSet.add(values[0]);
        }
        return resultSet;
    }

    private List<String> getLinesFromPath()
    {
        List<String> resultList = null;
        try
        {
            if (logDir != null)
            {
                File[] files = logDir.toFile().listFiles();
                if (files != null)
                {
                    for (File file : files)
                    {
                        resultList = Files.readAllLines(file.toPath(), Charset.defaultCharset());
                    }
                }
            }
        }
        catch (IOException e)
        {
        }
        return resultList;
    }

    private Date getDateFromString(String source)
    {
        Date date = null;
        SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
        try
        {
            date = dateFormat.parse(source);
        }
        catch (ParseException e)
        {
        }
        return date;
    }

    private List<String> getLinesBetweenDates(Date after, Date before)
    {
        List<String> list = getLinesFromPath();
        List<String> resultList = new ArrayList<>();
        if (list != null)
        {
            if (after == null && before == null)
            {
                for (String line : list)
                    resultList.add(line);
            } else if (after == null)
            {
                for (String line : list)
                {
                    String[] values = line.split("\\t");
                    Date dateFromLine = getDateFromString(values[2]);
                    if (dateFromLine != null && dateFromLine.compareTo(before) <= 0)
                        resultList.add(line);
                }
            } else if (before == null)
            {
                for (String line : list)
                {
                    String[] values = line.split("\\t");
                    Date dateFromLine = getDateFromString(values[2]);
                    if (dateFromLine != null && dateFromLine.compareTo(after) >= 0)
                        resultList.add(line);
                }
            } else
            {
                for (String line : list)
                {
                    String[] values = line.split("\\t");
                    Date dateFromLine = getDateFromString(values[2]);
                    if (dateFromLine != null && dateFromLine.compareTo(after) >= 0 && dateFromLine.compareTo(before) <= 0)
                        resultList.add(line);
                }
            }
        }
        return resultList;
    }


}