NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
Две опции, которые не требуют копирования полного набора:
for e in s:
break
# e is now an element from s
Или...
e = next(iter(s))
, Но в целом, наборы не поддерживают индексацию или разрезание.
Наименьшее количество кода было бы:
>>> s = set([1, 2, 3])
>>> list(s)[0]
1
, Очевидно, это создало бы новый список, который содержит каждого члена набора, таким образом, не большой, если Ваш набор является очень большим.
Так как Вы хотите случайный элемент, это будет также работать:
>>> import random
>>> s = set([1,2,3])
>>> random.sample(s, 1)
[2]
документация, кажется, не упоминает производительность random.sample
. От действительно быстрого эмпирического теста с огромным списком и огромным набором, это, кажется, постоянное время для списка, но не для набора. Кроме того, повторение по набору не случайно; порядок не определен, но предсказуем:
>>> list(set(range(10))) == range(10)
True
, Если бы случайность важна и Вам нужен набор элементов в постоянное время (большие наборы), я использовал бы random.sample
и преобразовал бы в список сначала:
>>> lst = list(s) # once, O(len(s))?
...
>>> e = random.sample(lst, 1)[0] # constant time
Я использую служебную функцию, которую я записал. Его имя является несколько вводящим в заблуждение, потому что это отчасти подразумевает, что мог бы быть случайный объект или что-то как этот.
def anyitem(iterable):
try:
return iter(iterable).next()
except StopIteration:
return None
Другая опция состоит в том, чтобы использовать словарь со значениями, о которых Вы не заботитесь. Например,
poor_man_set = {}
poor_man_set[1] = None
poor_man_set[2] = None
poor_man_set[3] = None
...
можно рассматривать ключи как набор за исключением того, что они - просто массив:
keys = poor_man_set.keys()
print "Some key = %s" % keys[0]
побочный эффект А этого выбора состоит в том, что Ваш код будет назад совместим с более старым, пред - set
версии Python. Это - возможно, не лучший ответ, но это - другая опция.
Редактирование: можно даже сделать что-то вроде этого для сокрытия того, что Вы использовали dict вместо массива или установили:
poor_man_set = {}
poor_man_set[1] = None
poor_man_set[2] = None
poor_man_set[3] = None
poor_man_set = poor_man_set.keys()
Чтобы представить некоторые временные характеристики различных подходов, рассмотрим следующий код. get () - это мое специальное дополнение к Python setobject.c, которое является просто pop () без удаления элемента.
from timeit import *
stats = ["for i in xrange(1000): iter(s).next() ",
"for i in xrange(1000): \n\tfor x in s: \n\t\tbreak",
"for i in xrange(1000): s.add(s.pop()) ",
"for i in xrange(1000): s.get() "]
for stat in stats:
t = Timer(stat, setup="s=set(range(100))")
try:
print "Time for %s:\t %f"%(stat, t.timeit(number=1000))
except:
t.print_exc()
Результат:
$ ./test_get.py
Time for for i in xrange(1000): iter(s).next() : 0.433080
Time for for i in xrange(1000):
for x in s:
break: 0.148695
Time for for i in xrange(1000): s.add(s.pop()) : 0.317418
Time for for i in xrange(1000): s.get() : 0.146673
Это означает, что для / break решение является самым быстрым (иногда быстрее, чем пользовательское решение get ()).