@Contract(pure = true)
  public static @Unmodifiable @NotNull <T> List<T> concat(@NotNull List<? extends T> list1, @NotNull List<? extends T> list2) {
    if (list1.isEmpty() && list2.isEmpty()) {
      return Collections.emptyList();
    }
    if (list1.isEmpty()) {
      //noinspection unchecked
      return (List<T>)list2;
    }
    if (list2.isEmpty()) {
      //noinspection unchecked
      return (List<T>)list1;
    }

    int size1 = list1.size();
    int size = size1 + list2.size();

    return new AbstractList<T>() {
      @Override
      public T get(int index) {
        return index < size1 ? list1.get(index) : list2.get(index - size1);
      }

      @Override
      public int size() {
        return size;
      }
    };
  }
@Contract(pure = true)
  public static @Unmodifiable @NotNull <T> List<T> concat(@NotNull List<? extends T> list1, @NotNull List<? extends T> list2)