📄 chapter17.html
字号:
<font color=#0000ff>if</font>(in.sval.equals(<font color=#004488>"import"</font>) ||
in.sval.equals(<font color=#004488>"package"</font>))
discardLine();
<font color=#0000ff>else</font> <font color=#009900>// It's an identifier or keyword</font>
identMap.add(fname, in.sval);
}
}
} <font color=#0000ff>catch</font>(IOException e) {
e.printStackTrace();
}
}
<font color=#0000ff>void</font> discardLine() {
<font color=#0000ff>try</font> {
<font color=#0000ff>while</font>(in.nextToken() !=
StreamTokenizer.TT_EOF
&& in.ttype !=
StreamTokenizer.TT_EOL)
; <font color=#009900>// Throw away tokens to end of line</font>
} <font color=#0000ff>catch</font>(IOException e) {
e.printStackTrace();
}
}
<font color=#009900>// StreamTokenizer's comment removal seemed</font>
<font color=#009900>// to be broken. This extracts them:</font>
<font color=#0000ff>void</font> eatComments() {
<font color=#0000ff>try</font> {
<font color=#0000ff>if</font>(in.nextToken() !=
StreamTokenizer.TT_EOF) {
<font color=#0000ff>if</font>(in.ttype == '/')
discardLine();
<font color=#0000ff>else</font> <font color=#0000ff>if</font>(in.ttype != '*')
in.pushBack();
<font color=#0000ff>else</font>
<font color=#0000ff>while</font>(<font color=#0000ff>true</font>) {
<font color=#0000ff>if</font>(in.nextToken() ==
StreamTokenizer.TT_EOF)
<font color=#0000ff>break</font>;
<font color=#0000ff>if</font>(in.ttype == '*')
<font color=#0000ff>if</font>(in.nextToken() !=
StreamTokenizer.TT_EOF
&& in.ttype == '/')
<font color=#0000ff>break</font>;
}
}
} <font color=#0000ff>catch</font>(IOException e) {
e.printStackTrace();
}
}
<font color=#0000ff>public</font> String[] classNames() {
String[] result = <font color=#0000ff>new</font> String[classes.size()];
Enumeration e = classes.keys();
<font color=#0000ff>int</font> i = 0;
<font color=#0000ff>while</font>(e.hasMoreElements())
result[i++] = (String)e.nextElement();
<font color=#0000ff>return</font> result;
}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> checkClassNames() {
Enumeration files = classMap.keys();
<font color=#0000ff>while</font>(files.hasMoreElements()) {
String file = (String)files.nextElement();
Vector cls = classMap.getVector(file);
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < cls.size(); i++) {
String className =
(String)cls.elementAt(i);
<font color=#0000ff>if</font>(Character.isLowerCase(
className.charAt(0)))
System.out.println(
<font color=#004488>"class capitalization error, file: "</font>
+ file + <font color=#004488>", class: "</font>
+ className);
}
}
}
<font color=#0000ff>public</font> <font color=#0000ff>void</font> checkIdentNames() {
Enumeration files = identMap.keys();
Vector reportSet = <font color=#0000ff>new</font> Vector();
<font color=#0000ff>while</font>(files.hasMoreElements()) {
String file = (String)files.nextElement();
Vector ids = identMap.getVector(file);
<font color=#0000ff>for</font>(<font color=#0000ff>int</font> i = 0; i < ids.size(); i++) {
String id =
(String)ids.elementAt(i);
<font color=#0000ff>if</font>(!classes.contains(id)) {
<font color=#009900>// Ignore identifiers of length 3 or</font>
<font color=#009900>// longer that are all uppercase</font>
<font color=#009900>// (probably static final values):</font>
<font color=#0000ff>if</font>(id.length() >= 3 &&
id.equals(
id.toUpperCase()))
<font color=#0000ff>continue</font>;
<font color=#009900>// Check to see if first char is upper:</font>
<font color=#0000ff>if</font>(Character.isUpperCase(id.charAt(0))){
<font color=#0000ff>if</font>(reportSet.indexOf(file + id)
== -1){ <font color=#009900>// Not reported yet</font>
reportSet.addElement(file + id);
System.out.println(
<font color=#004488>"Ident capitalization error in:"</font>
+ file + <font color=#004488>", ident: "</font> + id);
}
}
}
}
}
}
<font color=#0000ff>static</font> <font color=#0000ff>final</font> String usage =
<font color=#004488>"Usage: \n"</font> +
<font color=#004488>"ClassScanner classnames -a\n"</font> +
<font color=#004488>"\tAdds all the class names in this \n"</font> +
<font color=#004488>"\tdirectory to the repository file \n"</font> +
<font color=#004488>"\tcalled 'classnames'\n"</font> +
<font color=#004488>"ClassScanner classnames\n"</font> +
<font color=#004488>"\tChecks all the java files in this \n"</font> +
<font color=#004488>"\tdirectory for capitalization errors, \n"</font> +
<font color=#004488>"\tusing the repository file 'classnames'"</font>;
<font color=#0000ff>private</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> usage() {
System.err.println(usage);
System.exit(1);
}
<font color=#0000ff>public</font> <font color=#0000ff>static</font> <font color=#0000ff>void</font> main(String[] args) {
<font color=#0000ff>if</font>(args.length < 1 || args.length > 2)
usage();
ClassScanner c = <font color=#0000ff>new</font> ClassScanner();
File old = <font color=#0000ff>new</font> File(args[0]);
<font color=#0000ff>if</font>(old.exists()) {
<font color=#0000ff>try</font> {
<font color=#009900>// Try to open an existing </font>
<font color=#009900>// properties file:</font>
InputStream oldlist =
<font color=#0000ff>new</font> BufferedInputStream(
<font color=#0000ff>new</font> FileInputStream(old));
c.classes.load(oldlist);
oldlist.close();
} <font color=#0000ff>catch</font>(IOException e) {
System.err.println(<font color=#004488>"Could not open "</font>
+ old + <font color=#004488>" for reading"</font>);
System.exit(1);
}
}
<font color=#0000ff>if</font>(args.length == 1) {
c.checkClassNames();
c.checkIdentNames();
}
<font color=#009900>// Write the class names to a repository:</font>
<font color=#0000ff>if</font>(args.length == 2) {
<font color=#0000ff>if</font>(!args[1].equals(<font color=#004488>"-a"</font>))
usage();
<font color=#0000ff>try</font> {
BufferedOutputStream out =
<font color=#0000ff>new</font> BufferedOutputStream(
<font color=#0000ff>new</font> FileOutputStream(args[0]));
c.classes.save(out,
<font color=#004488>"Classes found by ClassScanner.java"</font>);
out.close();
} <font color=#0000ff>catch</font>(IOException e) {
System.err.println(
<font color=#004488>"Could not write "</font> + args[0]);
System.exit(1);
}
}
}
}
<font color=#0000ff>class</font> JavaFilter <font color=#0000ff>implements</font> FilenameFilter {
<font color=#0000ff>public</font> <font color=#0000ff>boolean</font> accept(File dir, String name) {
<font color=#009900>// Strip path information:</font>
String f = <font color=#0000ff>new</font> File(name).getName();
<font color=#0000ff>return</font> f.trim().endsWith(<font color=#004488>".java"</font>);
}
} <font color=#009900>///:~</font></PRE></FONT></BLOCKQUOTE>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The class <B>MultiStringMap</B> is
a tool that allows you to map a group of strings onto each key entry. As in the
previous example, it uses a
<A NAME="Index3036"></A><A NAME="Index3037"></A><B>Hashtable</B> (this time with
inheritance) with the key as the single string that’s mapped onto the
<B>Vector</B> value. The <B>add( )</B> method simply checks to see if
there’s a key already in the <B>Hashtable</B>, and if not it puts one
there. The <B>getVector( )</B> method produces a <B>Vector</B> for a
particular key, and <B>printValues( )</B>, which is primarily useful for
debugging, prints out all the values <B>Vector</B> by
<B>Vector</B>.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">To keep life simple, the class
names from the standard Java libraries are all put into a
<A NAME="Index3038"></A><B>Properties</B> object (from the standard Java
library). Remember that a <B>Properties</B> object is a <B>Hashtable</B> that
holds only<B> String</B> objects for both the key and value entries. However, it
can be saved to disk and restored from disk in one method call, so it’s
ideal for the repository of names. Actually, we need only a list of names, and a
<B>Hashtable</B> can’t accept <B>null</B> for either its key or its value
entry. So the same object will be used for both the key and the
value.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">For the classes and identifiers
that are discovered for the files in a particular directory, two
<B>MultiStringMap</B>s are used: <B>classMap </B>and <B>identMap</B>. Also, when
the program starts up it loads the standard class name repository into the
<B>Properties </B>object called <B>classes</B>, and when a new class name is
found in the local directory that is also added to <B>classes </B>as well as to
<B>classMap</B>. This way, <B>classMap</B> can be used to step through all the
classes in the local directory, and <B>classes</B> can be used to see if the
current token is a class name (which indicates a definition of an object or
method is beginning, so grab the next tokens – until a semicolon –
and put them into <B>identMap</B>).</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">The default constructor for
<B>ClassScanner</B> creates a list of file names (using the <B>JavaFilter</B>
implementation of
<A NAME="Index3039"></A><A NAME="Index3040"></A><B>FilenameFilter</B>, as
described in Chapter 10). Then it calls <B>scanListing( )</B> for each file
name.</FONT><BR></P></DIV>
<DIV ALIGN="LEFT"><P><FONT FACE="Georgia">Inside <B>scanListing( )</B>
the source code file is opened and turned into a
<A NAME="Index3041"></A><A NAME="Index3042"></A><B>StreamTokenizer</B>. In the
documentation, passing <B>true </B>to <B>slashStarComments( )</B> and
<B>slashSlashComments( )</B> is supposed to strip those comments out, but
this seems to be a bit flawed (it doesn’t quite work in Java
1.0<A NAME="Index3043"></A>). Instead, those lines are commented out and the
comments are extracted by another method. To do this, the ‘<B>/</B>’
must be captured as an ordinary character rather than letting the
<B>StreamTokenizer</B> absorb it as part of a comment, and the
<B>ordinaryChar( )</B> method tells the <B>StreamTokenizer </B>to<B> </B>do
this. This is also true for dots (‘<B>.</B>’), since we want to have
the method calls pulled apart into individual identifiers. However, the
underscore, which is ordinarily treated by <B>StreamTokenizer</B> as an
individual character, should be left as part of identifiers since it appears in
such <B>static</B> <B>final</B> values as <B>TT_EOF</B> etc., used in this very
program. The <B>wordChars( ) </B>method takes a range of characters you
want to add to those that are left inside a token that is being parsed as a
word. Finally, when parsing for one-line comments or discarding a line we need
to know whe
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -