• ,

Изменения в лекциях

Недавно в комментариях к какой-то теме один добрый человек выложил свои материалы, которые он писал, обучаясь тут. За что ему большое спасибо, но не помню, где это было, чтобы написать там.
Но дело не в этом. Произошла такая интересная история:
как и у многих, уровни начиная с 17 требуют много времени. Вот сижу, ковыряю. Доковыряла до задач 18ого уровня, прочитав лекции и половину доп.материалов. Смотрю задачу, понимаю, что решить ее можно несложно, но кажется велосипед. Думаю-думаю, ничего не придумывается кроме похожих на велосипед вещей. Думаю, а как ее решали до меня. Смотрю, все как один используют RandomAccessFile, о котором в лекциях ни слова. Только в доп.материалах. Мой велосипед на нем и основывался, но до некоторых вещей я своим умом не дошла. Думаю, надо получше почитать про это… где-то были тут материалы от доброго человека. Открываю, смотрю и понимаю, что раньше (похоже) это было в лекциях. А сейчас нет. А задача осталась.
Дело не в том, что непонятно как ее решать (хотя, конечно, некоторые непонятки могут возникать и иногда довольно сильно раздражают). Как-то грустно стало, что лекции урезали и я сейчас читаю эти урезанные лекции, а доп.информация впитывается не так хорошо, как лекции.

Если вдруг кто-то из администраторов сюда зайдет, было бы интересно узнать, почему так порезали лекции =(

Не давал покоя мне substring(..)

Собственно, по причине сабжа позволил себе покопаться в String.substring(..). И пришел, наверное, к неожиданным результатам, которыми решил поделиться с Вами, дорогие Джаворашовцы.
Представить на Ваш суд, так сказать.
Так вот.
Есть такое утверждение, что строка, созданная с помощью метода substring(..) использует массив символов исходной строки.
Вот, в частности, выдержка из недавно прочтенной статьи «Справочник по java. Статические строки» всеми уважаемого articles:
Есть замечание относительно метода substring — возвращаемая строка использует тот же байтовый массив, что и исходная
Ну и конечно Лекции джавараш. Вот цитаты из Декции 22:
Когда мы создаем подстроку с помощью метода substring, то создается новый объект String.
Но вместо того, чтобы хранить ссылку на массив с новым набором символов, этот объект хранит ссылку на старый массив символов и вместе с этим хранит две переменные, с помощью которых определяет – какая часть оригинального массива символов относится к нему.

Когда создается подстрока, массив символов не копируется в новый объект String. Вместо этого оба объекта хранят ссылку на один и тот же массив символов. Но! Второй объект хранит еще две переменных, в который записано с какого и сколько символов этого массива – его.

Поэтому, если ты возьмешь строку длинной 10,000 символов и наделаешь из нее 10,000 подстрок любой длинны, то эти «подстроки» будут занимать очень мало памяти, т.к. массив символов не дублируется. Строки, которые должны занимать кучу места, будут занимать буквально пару байт.
все понятно расписано, даже разжевано.
Но, так как я пытаюсь повысить знание английского, то часто обращаюсь к официальной документации, и вот там я как то не смог найти подтверждение сему факту… Списав это на свою невнимательность, я все таки заглянул в исходник substring() (благо IDEA позволяет это сделать одним нажатием кнопки).
public String substring(int beginIndex, int endIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        if (endIndex > value.length) {
            throw new StringIndexOutOfBoundsException(endIndex);
        }
        int subLen = endIndex - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return ((beginIndex == 0) && (endIndex == value.length)) ? this
                : new String(value, beginIndex, subLen);
    }

заинтригованный, я пошел дальше:

     * Allocates a new {@code String} that contains characters from a subarray
     * of the character array argument. The {@code offset} argument is the
     * index of the first character of the subarray and the {@code count}
     * argument specifies the length of the subarray. The contents of the
     * subarray are copied; subsequent modification of the character array does
     * not affect the newly created string.
    public String(char value[], int offset, int count) {
        if (offset < 0) {
            throw new StringIndexOutOfBoundsException(offset);
        }
        if (count < 0) {
            throw new StringIndexOutOfBoundsException(count);
        }
        // Note: offset or count might be near -1>>>1.
        if (offset > value.length - count) {
            throw new StringIndexOutOfBoundsException(offset + count);
        }
        this.value = Arrays.copyOfRange(value, offset, offset+count);
    }

где Arrays.copyOfRange — нативный метод, который возвращает копию массива из char…
Вполне себе тривиальный код, и мне показалось очевидным, что просто создается новая строка с новым набором chars. или я что то не учел…
Так до конца и не поверив в свои выводы, я решил как нибудь потестировать этот substring(), опираясь на фразу из лекции:
Поэтому, если ты возьмешь строку длинной 10,000 символов и наделаешь из нее 10,000 подстрок любой длинны, то эти «подстроки» будут занимать очень мало памяти...
только вместо 10_000 сделаем сразу 100_000_000, чего мелочиться. Накидал побыстрому такой код:

public class Test {
    public static void main(String[] args)
    {
        System.out.println("Начинаем:");
        print();
        System.out.println("********************************");
        char[]big=new char[100_000_000];//создаем нормальный такой массив
            int j=0;//и заполняем этот массив всякой ерундой
            for (int k=0;k<big.length;k++){
                if (j++<65535)big[j]=(char)k;
                else j=1;
            }
        String bigString=new String(big);//вот она, строка!
        System.out.println("создал большую строку bigString на основе массива big. Теперь:");
        print();
        List<String>list=new ArrayList<>();//здесь будут ссылки на строки, что бы сборщик мусора не удалял
                                           //не используемые, по его мнению, строки. 
        System.out.println("************************************");
        System.out.println("Теперь будем создавть подстроки с помощью substring(..) и наблюдать," +
                "что же происходит с памятью");
        for (int i = 2; i <10; i++)
        {
            //создаем подстроку, используя метод String.substring(..)
            String sub= bigString.substring(1,bigString.length()-1);
            //если этот метод не создает полностью новый массив символов, а только пользуется
            //исходным из bigString 
            // то при создании новой строки sub мы не будем наблюдать ощутипый расход памяти
            list.add(sub);//эти ссылки мы должны где нибудь хранить, иначе сборщик мусора
            //избавится от неипользуемых объктов String
            System.out.print(String.format("Создаем %d-ую подстроку, при этом ", i - 1));
            print();
        }
        System.out.println("***************************************");
        print();
    }
    static void  print(){
        System.out.println("Памяти используется "+(Runtime.getRuntime().totalMemory()
                - Runtime.getRuntime().freeMemory())/1024/1024 + " mb");
    }
}

и вот, что получилось:

Начинаем:
Памяти используется 0 mb
********************************
создал большую строку bigString на основе массива big. Теперь:
Памяти используется 382 mb
************************************
Теперь будем создавть подстроки с помощью substring(..) и наблюдать,что же происходит с памятью
Добавляем 1-ую подстроку, при этом Памяти используется 573 mb
Добавляем 2-ую подстроку, при этом Памяти используется 763 mb
Добавляем 3-ую подстроку, при этом Памяти используется 954 mb
Добавляем 4-ую подстроку, при этом Памяти используется 1145 mb
Добавляем 5-ую подстроку, при этом Памяти используется 1336 mb
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOfRange(Arrays.java:3658)
	at java.lang.String.<init>(String.java:201)
	at java.lang.String.substring(String.java:1956)
	at com.javarush.test.tests.Test.main(Test.java:42)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:483)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

Process finished with exit code 1

т.е. каждый раз при создании новой строки sub при помощи bigString.substring(..) массив символов, как раз ДУБЛИРУЕТСЯ. Иначе как объяснить такой рост расхода памяти?..
После этого лично у меня отпали всякие сомнения относительно работы метода String.substsring()
А у Вас?
  • ,

Проблема с лекцией и плагином

Уже несколько дней (с 21-го июля) при попытке перейти с первой лекции 15-го уровня на вторую выдает ошибку «query did not return a unique result: 2» Так же не могу отправить на проверку задачи из IDEA, так как там тоже получаю ошибку «Неизвестная ошибка при работе с сервером». Я сомневаюсь, что проблема где-то у меня, и больше склоняюсь к варианту, что это неполадки сервиса. Поэтому хотелось бы узнать, если кто-то в курсе, с чем это связано и когда будет исправлено?
  • ,

Поиск по лекциям

Добрый день. Прошу поделится способами поиска по лекциям материала.
Материала много, всё в голове трудно удержать, особенно новое, приходится либо гуглить(на удивление все вопросы гуглятся за 30 секунд), но всё же идеальный бы вариант был вернутся к определенной лекции и абзацу. Ctrl+F в лекциях не работает. Может еще как-то можно?