Java - локальный класс и дженерики, почему предупреждение компилятора?

Изменить 2019-03-07, чтобы справиться с расширенным набором данных OP

Это можно решить путем агрегирования в неэквивалентном самосоединении

library(data.table)
# coerce character dates to IDate class
cols <- c("start", "end")
setDT(df)[, (cols) := lapply(.SD, as.IDate), .SDcols = cols]
# non-equi self-join and aggregate
tmp <- df[df, on = .(id, start <= end, end >= start), .N, by = .EACHI]
# append counts to original dataset
df[, overlapping.rows := tmp$N]
df
        id      start        end overlapping.rows
 1: 174095 2018-12-19 2018-12-31                2
 2: 227156 2018-12-19 2018-12-31                1
 3: 210610 2018-04-13 2018-09-27                1
 4:  27677 2018-04-12 2018-04-26                2
 5: 370474 2017-07-13 2017-08-19                1
 6: 303693 2017-02-20 2017-04-09                1
 7:  74744 2016-10-03 2016-11-05                1
 8: 174095 2018-12-01 2018-12-18                2
 9:  27677 2018-03-01 2018-05-29                2
10: 111111 2018-01-01 2018-01-31                1
11: 111111 2018-11-11 2018-12-31                1
12: 174095 2018-11-30 2018-12-25                3
blockquote>

Используя , связывающий код, можно написать более компактным, но и более запутанным способом:

library(data.table)
cols <- c("start", "end")
setDT(df)[, (cols) := lapply(.SD, as.IDate), .SDcols = cols][
  , overlapping.rows := df[df, on = .(id, start <= end, end >= start), .N, by = .EACHI]$N][]
[1122 ] Обратите внимание, что часть для добавления результатов к оригиналу df основана на комментарии Фрэнка .


Моя первоначальная попытка использовать второе объединение для добавления результатов к исходному df потерпела неудачу в том случае, если есть разные значения для того же id, что и , указанного в OP . Это можно исправить, включив номер строки во второе объединение:

library(data.table)
# coerce character dates to IDate class
cols <- c("start", "end")
setDT(df)[, (cols) := lapply(.SD, as.IDate), .SDcols = cols]
# append row number
tmp <- df[, rn := .I][
  # non-equi self-join and aggregate
  df, on = .(id, start <= end, end >= start), .(rn = i.rn, .N), by = .EACHI]
# append counts to original dataset by joining on row number
df[tmp, on = "rn", overlapping.rows := N][, rn := NULL]
df
        id      start        end overlapping.rows
 1: 174095 2018-12-19 2018-12-31                2
 2: 227156 2018-12-19 2018-12-31                1
 3: 210610 2018-04-13 2018-09-27                1
 4:  27677 2018-04-12 2018-04-26                2
 5: 370474 2017-07-13 2017-08-19                1
 6: 303693 2017-02-20 2017-04-09                1
 7:  74744 2016-10-03 2016-11-05                1
 8: 174095 2018-12-01 2018-12-18                2
 9:  27677 2018-03-01 2018-05-29                2
10: 111111 2018-01-01 2018-01-31                1
11: 111111 2018-11-11 2018-12-31                1
12: 174095 2018-11-30 2018-12-25                3
blockquote>

Объяснение

Условие соединения в соединении без равенства выполняет трюк. Два интервала не перекрываются , если первый заканчивается до начала второго или первый интервал начинается после окончания второго интервала,

e 1 < s 2 ИЛИ e 2 < s 1

Теперь, если два интервала действительно пересекаются / перекрываются, то противоположное из вышеприведенного должно быть истинным. Отрицая и применяя закон Де Моргана , мы получаем условия

s 2 = e 1 И e 2 ]> = s 1

, которые используются в неравных объединениях .

Данные

Расширенный набор данных OP, как описано в РЕДАКТИРОВАНИИ ОП 2019-03-06:

library(data.table)
df <- fread("id     start     end
174095 2018-12-19 2018-12-31
227156 2018-12-19 2018-12-31
210610 2018-04-13 2018-09-27
27677  2018-04-12 2018-04-26
370474 2017-07-13 2017-08-19
303693 2017-02-20 2017-04-09
74744  2016-10-03 2016-11-05
174095 2018-12-01 2018-12-18
27677  2018-03-01 2018-05-29
111111 2018-01-01 2018-01-31
111111 2018-11-11 2018-12-31
174095 2018-11-30 2018-12-25")

5
задан Michael Myers 29 April 2009 в 14:43
поделиться

4 ответа

Теперь я убежден, что это ошибка javac. Приведенные выше решения, которые добавляют универсальный параметр в InIterator, который либо скрывает, либо заменяет E, бесполезны, поскольку они не позволяют итератору делать что-то полезное, например, возвращать элемент типа E - E. Stuff's.

Однако это компилируется без Предупреждения (спасибо Jorn за подсказку):

public class Stuff<E> {
  E bar;
  Iterator<E> foo() {
    class InIterator<Z> implements Iterator<E> {
      @Override public boolean hasNext() { return false; }
      @Override public E next() { return bar;  }
      @Override public void remove() { }
    }
    return new InIterator<Void>();
  }
}

Определенно ошибка.

1
ответ дан 14 December 2019 в 13:46
поделиться

Хм, здесь нет предупреждений.

import java.util.Iterator;

public class Stuff<E> {
    Iterator<E> foo() {
        class InIterator implements Iterator<E> {
            public boolean hasNext() {
                return false;
            }

            public E next() {
                return null;
            }

            public void remove() {
            }
        }
        return new InIterator();
    }

    public static void main(String[] args) {
        Iterator<String> i = new Stuff<String>().foo();
    }
}
1
ответ дан 14 December 2019 в 13:46
поделиться

Я считаю, что происходит то, что вы игнорируете аргумент универсального типа, называя InIterator без ссылки на универсальный в подписи (хотя он присутствует в интерфейсе).

Это относится к категории глупых предупреждений компилятора: вы написали класс так, что 100% экземпляров InIterator будут реализовывать Iterator , но компилятор не распознает это. (Я полагаю, это зависит от компилятора. Я не вижу предупреждения в моем компиляторе Eclipse, но я знаю, что компилятор Eclipse обрабатывает дженерики немного по-другому, чем компилятор JDK.)

Я утверждаю, что это менее понятно и менее близко к тому, что вы имеете в виду, но, возможно, более дружественно к компилятору и в конечном итоге эквивалентно:

public class Stuff<E> {
  Iterator<E> foo() {
    class InIterator<F> implements Iterator<F> {
      @Override public boolean hasNext() { return false; }
      @Override public E next() { return null; }
      @Override public void remove() { }
    }
    return new InIterator<E>();
  }
}
3
ответ дан 14 December 2019 в 13:46
поделиться

Yeah, I also agree that this should be a bug. If you "lift" the local class out of the method into a member class, it works fine too. And there isn't much difference between the two except different scoping and access to local variables.

public class Stuff<E> {
  class InIterator implements Iterator<E> {
    @Override public boolean hasNext() { return false; }
    @Override public E next() { return null; }
    @Override public void remove() { }
  }
  Iterator<E> foo() {
    return new InIterator();
  }
}
1
ответ дан 14 December 2019 в 13:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: