Как будто вы пытаетесь получить доступ к объекту, который является null
. Рассмотрим ниже пример:
TypeA objA;
. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException
, что имеет смысл.
См. Также этот пример:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Я использую для цикла для итерации строки и использования charAt()
, чтобы заставить каждый символ исследовать его. Так как Строка реализована с массивом, charAt()
, метод является постоянной операцией времени.
String s = "...stuff...";
for (int i = 0; i < s.length(); i++){
char c = s.charAt(i);
//Process char
}
Это - то, что я сделал бы. Это кажется самым легким мне.
, Насколько правильность идет, я не полагаю, что это существует здесь. Это - все на основе Вашего персонального стиля.
StringTokenizer является полностью неподходящим к задаче повреждения строки в ее отдельные символы. С String#split()
можно сделать это легко при помощи regex, который ничему не соответствует, например:
String[] theChars = str.split("|");
, Но StringTokenizer не использует regexes, и нет никакой строки разделителя, можно определить, что это не будет соответствовать ничему между символами. Там один милый небольшой взлом, который можно использовать для выполнения того же самого: используйте саму строку в качестве строки разделителя (делающий каждый символ в нем разделитель) и имейте его, возвращают разделители:
StringTokenizer st = new StringTokenizer(str, str, true);
Однако я только упоминаю эти опции в целях отклонения их. Оба метода повреждают исходную строку в одну символьную строку вместо символьных примитивов, и оба включают много издержек в форме создания объекта и обработки строк. Сравните это с вызовом charAt () в для цикла, который не подвергается фактически никаким издержкам.
Я не использовал бы StringTokenizer
, поскольку это - один из классов в JDK, это - наследие.
javadoc говорит:
StringTokenizer
класс прежней версии, который сохраняется по причинам совместимости, хотя ее использованию препятствуют в новом коде. Рекомендуется, чтобы любой ищущий эту функциональность использовал метод разделенияString
илиjava.util.regex
пакет вместо этого.
См. Учебные руководства по Java: Строки .
public class StringDemo {
public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
char[] tempCharArray = new char[len];
char[] charArray = new char[len];
// put original string in an array of chars
for (int i = 0; i < len; i++) {
tempCharArray[i] = palindrome.charAt(i);
}
// reverse array of chars
for (int j = 0; j < len; j++) {
charArray[j] = tempCharArray[len - 1 - j];
}
String reversePalindrome = new String(charArray);
System.out.println(reversePalindrome);
}
}
Помещенный длина в int len
и использование for
цикл.
Существуют некоторые специализированные классы для этого:
import java.text.*;
final CharacterIterator it = new StringCharacterIterator(s);
for(char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
// process c
...
}
Я соглашаюсь, что StringTokenizer является излишеством здесь. На самом деле я испытал предложения выше и не торопился.
Мой тест был довольно прост: создайте StringBuilder приблизительно с миллионом символов, преобразуйте его в Строку и пересеките каждого из них с charAt () / после преобразования в массив символов / с CharacterIterator тысячу раз (конечно, удостоверяющийся делать что-то на строке, таким образом, компилятор не может оптимизировать далеко целый цикл:-)).
результат на моем Powerbook на 2,6 ГГц (это - Mac:-)), и JDK 1.5:
Как результаты существенно отличается, самый простой путь также, кажется, самый быстрый. Интересно, charAt () StringBuilder, кажется, немного медленнее, чем тот Строки.
BTW я предлагаю не использовать CharacterIterator, поскольку я считаю его злоупотребление '\uFFFF' символом как "конец повторения" действительно ужасный взлом. В больших проектах всегда существует два парня, которые используют тот же вид взлома в двух различных целях и катастрофических отказах кода действительно загадочно.
Вот один из тестов:
int count = 1000;
...
System.out.println("Test 1: charAt + String");
long t = System.currentTimeMillis();
int sum=0;
for (int i=0; i<count; i++) {
int len = str.length();
for (int j=0; j<len; j++) {
if (str.charAt(j) == 'b')
sum = sum + 1;
}
}
t = System.currentTimeMillis()-t;
System.out.println("result: "+ sum + " after " + t + "msec");
Обратите внимание, что большинство других методов, описанных здесь, ломается, если Вы имеете дело с символами за пределами BMP (Unicode Основная Многоязычная Плоскость ), т.е. кодовые точки , которые являются за пределами диапазона u0000-uFFFF. Это будет только редко происходить, так как кодовые точки вне этого главным образом присвоены мертвым языкам. Но существуют некоторые полезные символы вне этого, например, некоторые кодовые точки, используемые для математической нотации, и некоторые раньше кодировали имена собственные на китайском языке.
В этом случае Ваш код будет:
String str = "....";
int offset = 0, strLen = str.length();
while (offset < strLen) {
int curChar = str.codePointAt(offset);
offset += Character.charCount(curChar);
// do something with curChar
}
Character.charCount(int)
метод требует Java 5 +.
Две опции
for(int i = 0, n = s.length() ; i < n ; i++) {
char c = s.charAt(i);
}
или
for(char c : s.toCharArray()) {
// process c
}
первое, вероятно, быстрее, тогда 2-й, вероятно, более читаемо.