Как стать автором
Обновить
163.38
ОК
Делаем продукт, который объединяет миллионы людей

Разбор задач JPoint 2019

Время на прочтение4 мин
Количество просмотров6.8K
image

Всем привет!

Закончилась одна из самых хардкорных конференций по Java – JPoint 2019, она проходила в седьмой раз и как всегда побила рекорд по посещаемости, в этот раз мероприятие привлекло более 1700 специалистов в области Java-разработки.

«Одноклассники» принимали участие во всех конференциях JPoint. Начиная с 2013 мы активно поддерживаем JPoint и на своих стендах устраиваем для участников различные активности по проверке знаний Java. В этом году у нас были знаменитые «нерешаемые» задачи от ведущих разработчиков OK.ru. Участники конференции, правильно ответившие на вопросы, получили призы.

Справедливости ради надо сказать, что из 600 листочков с задачами, которые мы раздали, обратно было получено менее 100, средний балл равен примерно 0.25.

Лучшим оказалось решение, набравшее 4 балла из 5 возможных.

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

Битам быть


Эту задачу решили 40%, сдавших ответы.

Михаил создаёт потокобезопасный аналог BitSet. Допишите реализацию метода setBit().

Для простоты можно считать размер BitSet постоянным.

public class ConcurrentBitSet {
    private final AtomicLongArray bits;
 
    public ConcurrentBitSet(int size) {
        assert size >= 0;
        int words = (size + 63) / 64;
        bits = new AtomicLongArray(words);
    }
 
    public void setBit(int index) {
        // TODO: Implement me!
    }
}

Решение
Реализация с помощью updateAndGet()/getAndUpdate(), доступных с Java 8, может выглядеть так:

public void setBit(int index) {
    int word = index >> 6;
    long mask = 1L << index;
    bits.updateAndGet(word, value -> value | mask);
}

Аналогично выглядит реализация на старом-добром compareAndSet():

public void setBit(int index) {
    int word = index >> 6;
    long mask = 1L << index;
    long oldValue;
    long newValue;
    do {
        oldValue = bits.get(word);
        newValue = oldValue | mask;
    } while (!bits.compareAndSet(word, oldValue, newValue));
}


Enum уже не тот


Эту задачу решили 45%, сдавших ответы.

Татьяна хочет проверить, являются ли два объекта константами одного и того же enum. Что она не учла?

boolean sameEnum(Object o1, Object o2) {
    return o1.getClass().isEnum() &&
            o1.getClass() == o2.getClass();
}

Решение
Подсказка кроется в документации к методу Enum.getDeclaringClass(), который используется, например, в Enum.compareTo():

public final Class<E> getDeclaringClass() {
    Class<?> clazz = getClass();
    Class<?> zuper = clazz.getSuperclass();
    return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}

Для enum-констант с непустыми телами создаются промежуточные классы, поэтому правильный ответ может выглядеть так:

boolean sameEnum(Object o1, Object o2) {
    return o1 instanceof Enum &&
            o2 instanceof Enum &&
            ((Enum) o1).getDeclaringClass() == ((Enum) o2).getDeclaringClass();
}


Некомпилируемые связи


Эту задачу решили 42%, сдавших ответы.

Имеется следующий интерфейс:

interface Link<T> {
    T next();
}

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

Link getTail(Link head) {
    if (head.next() == null) {
        return head;
    }
    return getTail(head.next());
}

Решение
Правильных минимальных ответов всего три:

<T extends Link<T>> Link<T> getTail(Link<T> head)
<T extends Link<T>> Link<T> getTail(T head)
<T extends Link<T>> T getTail(T head)

Как это ни парадоксально выглядит, такая сигнатура не по зубам компилятору Java:

<T extends Link<T>> T getTail(Link<T> head)


Мессенджер


Эту задачу решили 14%, сдавших ответы.

Костя разрабатывает приложение для обмена сообщениями. Укажите ошибки в методе для отправки сообщения по сети.

void send(SocketChannel ch, String message) throws IOException {
    byte[] bytes = message.getBytes();
 
    ByteBuffer header = ByteBuffer.allocate(4);
 
    header.putInt(bytes.length);
    ch.write(header);
    ch.write(ByteBuffer.wrap(bytes));
}

Решение
В этом коде имеются как минимум три ошибки:


Так может выглядеть исправленная версия:

void send(SocketChannel ch, String message) throws IOException {
    byte[] bytes = message.getBytes(StandardCharsets.UTF_8);

    ByteBuffer header = ByteBuffer.allocate(4);
    header.putInt(bytes.length);
    header.flip();

    while (header.hasRemaining()) {
        ch.write(header);
    }

    ByteBuffer body = ByteBuffer.wrap(bytes);
    while (body.hasRemaining()) {
        ch.write(body);
    }
}


Java в контейнере


Эту задачу решили 7.5%, сдавших ответы.

Какие параметры JVM следует прописать Алексею, чтобы не позволить ОС Linux убить Java-процесс из-за превышения лимита памяти, отведённого на контейнер?

  • -Xmx
  • -XX:MaxMetaspaceSize
  • -XX:ReservedCodeCacheSize
  • -XX:+UseContainerSupport
  • -XX:MaxRAMPercentage
  • Память JVM нельзя ограничить

Решение
Память, потребляемая Java-процессом, далеко не ограничивается только хипом, Metaspace и Code Cache. Многие другие структуры JVM также занимают память, причём не все из них регулируются настройками. Помимо виртуальной Java машины нативную память выделяет Java Class Library и пользовательский код посредством Direct ByteBuffers и Mapped ByteBuffers.

Параметр UseContainerSupport совместно с MaxRAMPercentage влияет лишь на размер хипа. Таким образом, нет гарантированного способа избежать превышения лимита только с помощью флагов JVM, и правильным ответом будет последний. Подробнее об использовании памяти Java процессом можно посмотреть в докладе Андрея Паньгина на Joker 2018 «Память Java процесса по полочкам».
Теги:
Хабы:
+24
Комментарии2

Публикации

Информация

Сайт
oktech.ru
Дата регистрации
Дата основания
Численность
201–500 человек
Местоположение
Россия
Представитель
Юля Новопашина