#1
Имеем цикл
while (count < 4) - который опирается на значение count, которое никогда внутри цикла не меняется. Значит цикл бесконечный. Например попав в цикл с count = 3 - count всегда будет оставаться = 3, значит условия цикла будет верно, значит мы будем в нем кружиться до тепловой смерти вселенной.П.С. Вообще бесконечные циклы - это нормально, до тех пор пока в них у вас описаны способы выхода, в один из которых можно гарантированно прийти - это может быть и break и return, выброс исключения, да даже простихосспаде System.exit(0) - что угодно, лишь бы из цикла можно было как-то выбраться. Либо рассчитывайте на то что приложение придется прерывать вручную.
#2
return capitalized / words.size() < 0.2;Тут пара проблем. Во-первых - можно нарваться на ArithmeticException при делении на 0.
Но важнее здесь то что при делении capitalized / words.size() происходит деление целого числа (int) на целое число (int) и результатом будет тоже int, а значит никаких дробей мы ни при каком раскладе не получим и сравнение не принесет того смысла который мы хотели. Например:
capitalized = 1;
words.size() = 5;
capitalized / words.size() = 1 / 5 = 0 - потому что произошло целочисленное деление.
Решением может стать явное преобразование одного из int к double, что бы результат деления тоже дал double:
return (double) capitalized / words.size() < 0.2;#3
if (endKey[i] < 0xff) - вот корень зла. Здесь мы имеем условие, которое будет выполняться всегда - а значит либо это условие описано неправильно, либо if тут вообще лишний. Почему условие будет выполняться всегда? Разбираем значения и типы данных:byte[] endKey - массив байт, endKey[i] - один байт из массива, может хранить значение от -128 до 1270xff - число в 16-ричной форме записи, в человеческом виде это число 255.Собственно, читаем исходную строку кода с if новым взглядом:
if (endKey[i] < 0xff)if ([значение от -128 до 127] меньше [255]) - очевидно что это условие будет выполняться всегда.
#4
Проблема кроется в этой строке:
val = val | (1 << j);Начну с вводной. Часть
1 << j - по сути аналог математического выражения 2^j (2 в степени j). В Java нет оператора степени, но есть метод Math.pow(). Без оператора побитового сдвига строчка кода выше могла бы выглядеть как:val = val | (1 * Math.pow(2, j));или просто
val = val | Math.pow(2, j);Почему тут вообще решено было использовать операцию левого битового сдвига << ? Многим эта тема кажется стремной и неоправданной, но представьте что ваш метод - "горячий", его вызовы в приложении происходят по 10000 раз в секунду, а то и больше - тогда конечно вы будете гнаться за каждой милисекундой в ущерб читаемости. Загляните ради любопытства в реализацию метода Math.pow() - и ужаснитесь сколько всего там происходит. Оператор же побитового сдвига прост как сапог - двигает биты в памяти влево на N позиций.
Поэтому побитовый сдвиг может заменять обычные арифметические операции умножения/деления числа на двойку или степени двойки когда вам реально нужен скоростной код. Кейс правда точно не про обычные API/UI автотесты, у нас таких жестких требований к производительности не будет почти никогда.
Теперь про причину ошибки в упомянутой строке - проблема в интовом типе 1 (единицы) в выражении:
val = val | (1 << j);Все числовые литералы - неявно int-ы (если только у них не указаны постфиксы: L, l (для long), D, d (для double), F, f (для float)).
1 << j - означает что единица целочисленного 4-байтного типа (т.е. 00000000 00000000 00000000 00000001 в двоичном виде) будет сдвинута на j разрядов влево. Например:1 << 2 = 00000000 00000000 00000000 00000100 в двоичной системе = 81 << 13 = 00000000 00000000 00100000 00000000 в двоичной системе = 8192Если j окажется больше или равно 31 - мы получим переполнение типа, знакомое нам и по обычным арифметическим операциям (ну например System.out.println(2000000000 + 2000000000); //result: -294967296).