Как стать автором
Обновить
170.26
JUG Ru Group
Конференции для Senior-разработчиков

Новый суперблиц по Java-хардкору

Время на прочтение 4 мин
Количество просмотров 27K
Итак, вчера мы с вами поиграли в джавовский вариант «Интеллектуальное казино против знатоков», и при этом, при всем уважении к хабровчанам, телезрители выиграли! Победителем этого этапа стал Сергей SerCe Целовальников, решивший три задачи. Как и обещали — мы вручаем ему небольшой приз: VIP-билет на JPoint!

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

Под катом — ответы на вчерашний раунд и суперблиц! Против знатоков сегодня играет телезритель из Петербурга Андрей apangin Паньгин.





Но сначала ответы на вчерашние задачи.

Различные аспекты от Николая Гарбузова
Скомпилируется ли следующий аспект AJC компилятором?
Если да — то что он выведет на консоль при компиляции?

public aspect QuizAspect {
    public static int count(int i) {
        return i++;
    }

    before (int n) : execution(public int QuizAspect.count(int)) 
            && args(n) && if(QuizAspect.count(1)>1) {
        System.out.println("QuizAspect " + n);
    }
}


Правильный ответ. Скомпилируется успешно, но ничего не выведет на консоль при компиляции. При этом вызов метода Quiz.count в рантайме приведет к StackOverflowError ошибке!

Можно подумать, что выражение в if() начнет выпоняться при компиляции кода, но это не так.
(не стоит путать аспекты с мета программированием)
Аспект лишь встроит код совета внутрь метода count, добавит if() к этому коду.


Выражения от Владимира Ситникова
В чём подвох удалять Java-комментарии таким выражением? Укажите 3 причины, почему так делать нельзя. (считаем, что исходник написан нормальными символами) —
Pattern.compile("/\\*(?:[^*]|\\*[^/])*\\*/")


Ответ
  1. Если это джавовская строка, а в ней якобы комент — то не будет работать
  2. Если комент заканчивается на две звездочки слэш, то работать не будет
  3. Если комментарий большой, то получим Будет StackOverflowError, т.к. java regexp’ы используют backtracking.


Пофиксить можно двумя способами:
  • Possessive quantifier:
    Pattern.compile("/\\*(?:[^*]|\\*(?!/))*+\\*/")
  • Independent group:
    Pattern.compile("/\\*(?>,[^*]|\\*(?!/))*\\*/")


Спринговые контексты от Николай Алименкова
Есть 2 Spring контекста:

1. a.xml с бином

<util:list id="myList">        
    <value>3</value>        
    <value>4</value>    
</util:list>


2. b.xml с бином

<util:list id="myList">
    <value>6</value>
</util:list>


Что напечатает такой фрагмент кода:

System.out.println(new ClassPathXmlApplicationContext("a.xml", "b.xml").getBean("myList"));


И как можно заставить его бросить ошибку, не изменяя логику работы кода?

Ответ
Выведет 6, а заставить бросить ошибку можно установив allowBeanDefinitionOverriding у контекста в false.


А теперь самая хардкорная задача вчерашнего дня, по мнению президента, премьера и министра обороны элитарного клуба.
OOM от Никиты Сальникова-Тарновского
Ниже приведены 2 программы. Каждая из них пытается аллоцировать суммарно памяти больше размера хипа. Но одна из них выкидывает java.lang.OutOfMemoryError, а вторая нет. Почему?

public class OOM1 {
    private static final int SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.55);

    public static void main(String[] args) {
        {
            byte[] bytes = new byte[SIZE];
            System.out.println(bytes.length);
        }

        byte[] bytes1 = new byte[SIZE];
        System.out.println(bytes1.length);

        System.out.println("I allocated memory successfully");
    }
}

public class OOM2 {
    private static final int SIZE = (int) (Runtime.getRuntime().maxMemory() * 0.35);

    public static void main(String[] args) {
        {
            byte[] bytes = new byte[SIZE];
            System.out.println(bytes.length);
        }

        byte[] bytes1 = new byte[SIZE];
        System.out.println(bytes1.length);

        byte[] bytes2 = new byte[SIZE];
        System.out.println(bytes2.length);

    System.out.println("I allocated memory successfully");
    }
}



Ответ
В обоих случаях javac понимает, что переменная bytes не будет использована после окончание внутреннего блока. Поэтому второй созданный массив, который мы кладем в переменную bytes1, займет тот же слот, что и переменная bytes. Как следствие, после выполнения присваивания bytes1 < — new bytes[SIZE] значение, которое было в переменной bytes становится недоступным и GC может его удалить. Тем самым OOM2 требует всего лишь 70% от хипа, а не 105%.

Update 1
Вот интересный анализ от cheremin на тему этой задачи.

Update 2
Для тех, у кого оба варианта бросают OOM: для воспроизведения бага запускайте вашу JVM с опцией -server

Груви от Баруха Садогурского и Спринг от Жени Борисова
А вот тут нас ждет облом. jbaruch и EvgenyBorisov попросили меня сохранить интригу и не публиковать ответы на их задачи до JPoint. Сказали, чтобы все желающие узнать ответы приходили на их доклады.

Желающие узнать ответы — попробуйте написать им в личку. Может быть они сжалятся над вами!


Суперблиц от Андрея Паньгина
Вот и настало время истинного хардкора! Знатоки поднимают глаза вверх, и на их экранах появляется улыбающийся apangin. Он кагбэ машет всем знатокам и кидает им тысячи воздушных поцелуев.

Вопрос первый
Что не так с этим кодом? Как его исправить?

    public static double[] getRandomVector(int size) {
        double[] vector = new double[size];
        Arrays.parallelSetAll(vector, i -> Math.random());
        return vector;
    }



Вопрос второй
Как такое может быть, что публичный метод работает заметно быстрее идентичного приватного?

public class Modifiers {
    static final Inner inner = new Inner();
 
    static class Inner {
        int x = 1;
 
        int getX1() { return x; }
        int getX2() { return getX1(); }
        int getX3() { return getX2(); }
        int getX4() { return getX3(); }
        int getX5() { return getX4(); }
        int getX6() { return getX5(); }
        int getX7() { return getX6(); }
        int getX8() { return getX7(); }
        int getX9() { return getX8(); }
 
        private int getPrivate() { return getX9(); }
        public int getPublic()   { return getX9(); }
    }
 
    @Benchmark
    public int testGetPrivate() {
        return inner.getPrivate();
    }
 
    @Benchmark
    public int testGetPublic() {
        return inner.getPublic();
    }
}



Вопрос третий
Можно ли в Java создать класс (именно класс, не интерфейс) без единого конструктора, даже приватного?


Такие дела!

Ваши ответы пишите ниже в комментариях под спойлером. У вас есть 12 часов. Первый, кто решит все три задачи, получит специальный приз от Андрея и Одноклассников. Остальные решившие все три задачи получат памятные призы от JUG.ru.

Удачи!

UPDATE:
Победил lany. Его ответы можете найти ниже в каментах! А вот как его награждали:

Теги:
Хабы:
+22
Комментарии 33
Комментарии Комментарии 33

Публикации

Информация

Сайт
jugru.org
Дата регистрации
Дата основания
Численность
51–100 человек
Местоположение
Россия
Представитель
Алексей Федоров