Pull to refresh
44
0.1
Валерий Вырва @valery1707

Java backend

Send message

А он работает не в ДефолтСити?

никак не следует что поднятие пенсионного возраста было выполнено в следствии появления этого средства.

Это очень вероятно, но не гарантировано, вы правы. Может быть там ещё какое-то странное событие произошло, из-за которого поменяли возраст.

«После» не значит «вследствие».
То что вам что-то кажется очень вероятным, ещё не значит что это что-то действительно очень вероятно.


Если исходить из того что есть в рассказе:


  • пенсионеры: работают
  • средняя продолжительность жизни: 69 лет
  • пенсионный возраст: подняли до 120
  • омолаживающий препарат не получил распространения: да есть в аптеках, и его всюду рекламируют, но при этом в отделе из трёх человек про него знает только одна, а остальные даже не слышали
  • гос.аппарат знает и принимает факт кардинального омоложения: но при этом на местах об этом знают только единицы
  • нет явного указания о причинах повышения возраста: при этом обсуждающие этот факт никак не связывают это увеличение с омоложением

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


Именно из-за него. Какие другие причины вы видите?

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

Очень даже меняет.
Мой ответ был про ситуацию в которой вы готовы "отдать долг родине", которая лишила вас пенсии, подняв пенсионный возраст до 120 лет, но взамен дала молодость и силы по такой низкой цене, что даже занимать до зарплаты не надо., только с учётом того что это не родина дала силы и молодость, но именно родина лишила пенсии.
А вы переходите на налоги, пенсию и содержание.
В исходном рассказе пенсионный возраст поднимался не из-за появления средства для омоложения.
Да, средство в продаже появилось до поднятия пенсионного возраста до 120 лет, но в этот момент средняя продолжительность жизни была 69 лет (это следует из того что омолодившаяся сотрудница ушла в отпуск и омолодилась до разговора об поднятии пенсионного возраста). Но из этого никак не как не следует что поднятие пенсионного возраста было выполнено в следствии появления этого средства.
При этом средство для омоложения связано с правительством только тем, что оно не запретило его продажу. Оно вообще может идти как БАД, а не реальное лекарство.
До сих пор хочется повторно отдать долг родине?

Так в рассказе не говорится что именно родина дала молодость и силы по такой цене.

Логика, по которой выполнение «обещаний» даёт крошечный прирост преданности, а провал обещания – несоизмеримо огромный рост недовольства. Так что быстро становится понятно, что обещаний лучше вообще не давать. Тем более, они повторяются снова и снова, одни и те же.

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

В данном примере преимуществ совсем не видно, так как всё вот это ваше многословие реализуется через указание аннотаций @NotNull @NotBlank

Для начала меня удивило что при поиске по строке Сбербанк/сбербанк мне сказали просто No more contacts и только по Банк с он таки нашёл банки.


Во-вторых, я добавил себе ботов Банк Сбербанк и Банк Тинькофф и уже минут 10 они висят со статусом Ожидание авторизации

Предположим, мы показываем 10 элементов на странице.
И если мы хотим перейти на страницу 3, то нужно пропустить первые 30 элементов.

По логике:


  • первая страница отображает первые 10 элементов
  • вторая — вторые 10, то есть с 11 по 20
  • третья (на которую мы и переходим) — третьи 10, то есть с 21 по 30

И вот чтобы отобразить элементы 3-й страницы необходимо пропустить первые 20 элементов.

Они не знают, что каждую фотографию потом еще перепроверяют вручную модераторы.

Так ведь это написано в разделе про фото-верификацию спамеров.
То есть чтобы твоя фотография была проверена модератором нужно:


  • попасть в список спамеров
  • заметить это (см. Stealth/Shadow ban)
  • подать жалобу (или как оно там называется) на выход из спам-листа
  • дойти до этапа фото-верификации (не думаю что он первый и единственный)
  • пройти нейросеть анализирующую фото (не думаю что 100% фото идёт на модераторов, наверняка самый трэш отсеивают)
  • и только теперь на вас посмотрит модератор

Так что там будет явно не 390 миллионов фотографий.

Если точнее, то реализация SimpleJpaRepository#findAll(java.lang.Iterable<ID>) возвращает разные типы коллекций, в зависимости от значения аргумента и структуры сущности:


  • null: java.util.Collections.EmptyList
  • пустая коллекция: java.util.Collections.EmptyList
  • сущность имеет композитный ключ: java.util.ArrayList из всех результатов SimpleJpaRepository#findOne(ID)
  • сущность с некомпозитным ключом: то что вернёт ниже лежащий уровень, в случае с Hibernate это:
    • java.util.Collections.EmptyList: не совсем ясно когда это возможно, но в org.hibernate.internal.SessionImpl#list(java.lang.String, org.hibernate.engine.spi.QueryParameters) есть такой флоу — не уверен на сколько он реалистичен
    • java.util.ArrayList: если дело дошло до выполнения запроса

Это можно представить в виде двух ответов на вопрос нужно ли реально выполнять запрос на БД:


  • нет: java.util.Collections.EmptyList и хватит с вас
  • да: java.util.ArrayList

и опять же — никакой магии.

Т.е. получается, что если меняется тип возвращаемого значения, то его нужно менять в двух местах…

Вы сейчас о чём?
Во всех вариантах метода getUsersForGroup тип (UserEntity) упоминается 1 раз — в джеренике на возвращаемом листе. Ну и ещё раз он, естественно присутствует в дженерике листа у UserRepository#findUsersByGroup.
Да, это два места. Но если мы меняем название класса сущности то, естественно, в обоих местах его и нужно будет сменить.


И я не понимаю как вопрос а что возвращает getUsersForGroup(Long) когда ни одного пользователя не найдено? превратился в если меняется тип возвращаемого значения, то его нужно менять в двух местах?


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

Где там магия?


  • снаружи просят список пользователей для группы
  • у нас (это проистекает из логики реализации) пользователь обязан иметь группу (то есть мы не интерпретируем группу null как пользователи без группы)
  • Так что мы разделяем логику на два ветки, в зависимости от значения идентификатора группы:
    • null: пустая коллекция, так как мы сразу и заранее знаем что нет таких пользователей
    • не null: запрос в БД, который всегда возвращает коллекцию

В результате метод всегда возвращает коллекцию и никогда null.
По факту на метод можно (и нужно, раз уж они упоминаются в статье) добавить аннотацию @Nonnull.


Опять же на счёт магии запроса к БД: нет там магии.
Мы выполняем запрос в БД вида (упрощённо) SELECT * FROM user WHERE group_id = ? и этот запрос, при любом значении параметра, любоая БД обработает одинаково и без магии — вернёт коллекцию строк подходящих под наше условие. И да, в некоторых случаях эта коллекция может быть пустой и это нормально.

Так о чём статья-то?
Затронуты ММО и тестирование, причём про тестирование рассказано даже больше чем про ММО.

Да, я как раз про это: все возвращают пустую коллекцию если запрос вернул 0 записей.
В том смысле что ответ на исходный вопрос пустая коллекция, но не потому что так делает Spring Data, а потому что так делают все и всегда и нет причин по которым кто-то будет отдавать что-то другое кроме пустой коллекции.
Возможно dskozin предположил что UserRepository#findUsersByGroup может возвращать null по аналогии с методами возвращающими одиночный объект. Но тут как раз все нормально: если мы не можем найти объект, то представлением пустого результата будет как раз null за неимением лучшего варианта. А для коллекций пустой result set запроса это пустая коллекция.


Если перевести все запросы возвращающие одиночный объект на Optional<T> то там тоже можно избавиться от null.
Вот это как раз умеет Spring Data.

В случае с orElse метод Collections.emptyList() будет вызван в любом случае был ли у нас null на входе или нет, а в случае с orElseGet в него будет передан method reference который будет вызван только при необходимости.
Это алгоритмическая разница. Есть ли разница в производительности — я не измерял, и возможно orElse(Collections.emptyList()) будет даже эффективнее orElseGet(Collections::emptyList).
Но тут вопрос в том как будет в дальнейшем использоваться результат выполнения getUsersForGroup — ведь коллекцию, полученную из Collections.emptyList(), нельзя модифицировать. А если нам нужна такая возможность, то orElseGe(Collections::emptyList) можно заменить на orElseGet(ArrayList::new) и тут уже будет явный профит, по сравнению с orElse(new ArrayList())

Так делает, на сколько я помню, не сам Spring Data, но и вообще любой ORM-маппинг, да и вообще чистый JDBC.

А вот тут


static <T, Q extends Query> void setParams(
  Map<String, Collection<T>> paramMap,
  Set<String> notReplacedParams,
  Q query) {
    Set<String> params = paramMap.keySet();
    notReplacedParams.stream()
      .filter(params::contains)
      .forEach(param -> query.setParameter(param, paramMap.get(param)));
}

нет необходимости в отдельной переменной, так как вместо params::contains можно сделать сразу paramMap.keySet()::contains.


P.S.
А ещё этот тот самый void-метод меняющий состояние аргумента.

А вот тут


try {
  FileChannel sc = new FileInputStream(src).getChannel();
  FileChannel dc = new FileOutputStream(new File(targetName)).getChannel();
  sc.transferTo(0, sc.size(), dc);
  dc.close();
  sc.close();
} catch (IOException ex) {
  log.error("ой", ex);
}

, кроме всего уже описанного, можно не закрыть один и даже оба канала, что чревато всякими бяками.
И, в случае отсутствия библиотечных функций, для таких вещей, как минимум, необходимо использовать try-with-resources. Благо он появился уже очень давно.

А вот ваш исходный


List<UserEntity> getUsersForGroup(Long groupId) {
  Optional<Long> optional = Optional.ofNullable(groupId);

  if (optional.isPresent()) {
    return userRepository.findUsersByGroup(optional.get());
  }

  return Collections.emptyList();   
}

я бы преобразовал в


List<UserEntity> getUsersForGroup(Long groupId) {
  return Optional
    .ofNullable(groupId)
    .map(userRepository::findUsersByGroup)
    .orElseGet(Collections::emptyList);
}

вместо вашего варианта:


List<UserEntity> getUsersForGroup(Long groupId) {
  if (groupId == null) {
    return Collections.emptyList();
  }

  return userRepository.findUsersByGroup(groupId);
}
Многим раз в год ЭКГ делают (даже под нагрузкой, если попросить) в рамках диспансеризации.

Так диспансеризация у нас 1 раз в 3 года, и только у некоторых категорий граждан каждый год.

Information

Rating
3,805-th
Location
Воронеж, Воронежская обл., Россия
Date of birth
Registered
Activity