Vectors
Vector Methods
Stepping Through a Vector
Example: Finding Words in a String
A String Buffer Example
Vectors and Threads
Enumerations
Synchronization Across Objects
Summary of Programs
Next Topic: GirdBagLayout
There are several ways of doing this:
b = new int[2*a.length]; for (int i=0; i < a.length; i++) b[i] = a[i]; a = b;
Vector v; v = new Vector();You must import java.util.Vector or java.util.*.
A vector can hold any reference type.
The elements of a vector do not have to have the same type.
Vector v; Point P; v = new Vector(); for (int i=0; i < 10; i++) v.addElement(new Point(i,i+1)); for (int i=0; i < v.size(); i++) { p = (Point)v.elementAt(i); System.out.println("Point has coordinates "+p.x+" and "+p.y); }
For our purposes, words are delimited by anything with an ASCII code of a blank or less. Here is some code for doing this.
import java.util.*; import java.io.*; class Vector1 { private static String readString(String s) { File f; FileInputStream fi; int len; byte[] b; f = new File(s); len = (int)f.length(); try { fi = new FileInputStream(f); } catch (FileNotFoundException e) { System.out.println("Cannot find file "+s); return ""; } System.out.println("File has length "+len); b = new byte[len]; try { if (fi.read(b) != len) { System.out.println("Error reading from file "+s); return ""; } } catch (IOException e) { System.out.println("Error reading from file "+s); return ""; } System.out.println("File reading done"); return new String(b); } private static boolean delimTest(char c) { if (c < = ' ') return true; return false; } private static int skipDelims(String s, int i) { while ( (i < s.length()) && delimTest(s.charAt(i)) ) i++; return i; } private static void setTokens1(Vector v, String s) { String s1; char c; int i; s1 = ""; i = skipDelims(s,0); while (i < s.length()) { c = s.charAt(i); if ( delimTest(c) ) { v.addElement(s1); i = skipDelims(s,i); s1 = ""; } else { s1 = s1 + s.charAt(i); i++; } } if (s1.length() > 0) v.addElement(s1); } public static void main(String args[]) { String str; String infile = "test.in"; Vector v; long time1; long time2; if (args.length < 1) System.out.println("using default file "+infile); else infile = args[0]; v = new Vector(); str = readString(infile); time1 = System.currentTimeMillis(); setTokens1(v,str); time2 = System.currentTimeMillis(); System.out.println("Vector size is "+v.size()); System.out.println("Time for conversion in milliseconds: "+(time2-time1)); } }Here are the results of running this on a file of moderate size:
java Vector1 using default file test.in File has length 202171 File reading done Vector size is 23800 Time for conversion in milliseconds: 736Why does this take so long?
Here is a fix that is in Vector2.java
private static int skipDelims(String s, int i) { while ( (i < s.length()) && delimTest(s.charAt(i)) ) i++; return i; } private static int skipRegular(String s, int i) { while ( (i < s.length()) && !delimTest(s.charAt(i)) ) i++; return i; } private static void setTokens2(Vector v, String s) { String s1; char c; int i; int j; s1 = ""; i = skipDelims(s,0); while (i < s.length()) { j = skipRegular(s,i); if (j > i) v.addElement(s.substring(i,j)); i = skipDelims(s,j); } }Here are the results of running this on the same input:
java Vector2 using default file test.in File has length 202171 File reading done Vector size is 23800 Time for conversion in milliseconds: 129
Here is another way that uses the Java StringTokenizer:
private static void setTokens3(Vector v, String s) { StringTokenizer st; st = new StringTokenizer(s); while (st.hasMoreTokens()) v.addElement(st.nextToken()); }This is the result of running it:
java Vector2st using default file test.in File has length 202171 File reading done Vector size is 23800 Time for conversion in milliseconds: 198
Consider the following code which can be added to the above example and is very inefficient:
str = ""; for (int i=0; i < v.size(); i++) { str = str + (String)v.elementAt(i) + " "; }A better solution is:
StringBuffer sb; sb = new StringBuffer(); for (int i=0; i < v.size(); i++) { sb.append((String)v.elementAt(i) + " "); } str = sb.toString();Here are the timing results on the same file as before using a StringBuffer:
java Vector2sb using default file test.in File has length 202171 File reading done Vector size is 23800 Time for making tokens in milliseconds: 128 String now has length 174738 Time for conversion to a string in milliseconds: 190What do you think the time would be for the first method?
java Vector2s using default file test.in File has length 202171 File reading done Vector size is 23800 Time for conversion in milliseconds: 129 String now has length 174738 Time for conversion in milliseconds: 77034Yes, that is 77,034 milliseconds, or 77 seconds, compared to 190 ms
That is 400 times as long.
However, care must still be taken.
Consider the following application:
import java.util.*; import java.io.*; class Vector3 { public static void showVector(Vector v) { String str; for (int i=0;i < v.size();i++) { try { Thread.sleep(100); } catch (InterruptedException e) {} str = (String)v.elementAt(i); System.out.println(i+" :"+str); } } public static void main(String args[]) { Vector v; BusyThread t; v = new Vector(); t = new BusyThread(v,1000); t.start(); for (int i=0;i < 10;i++) { System.out.println("Vector had size "+v.size()); showVector(v); System.out.println("Vector has size "+v.size()); try { Thread.sleep(1000); } catch (InterruptedException e) {} } } }BusyThread just adds to and removes elements from a vector at random:
import java.util.*; class BusyThread extends Thread { Vector v; int count; public BusyThread(Vector v, int count) { this.v = v; this.count = count; } public void run() { double ran; for (int i=0;i < count;i++) { ran = Math.random(); if (ran > 0.5) v.addElement("abcdef"+i); else if (v.size() > 0) v.removeElementAt(0); try { sleep(10); } catch (InterruptedException e) {} } } }The timing is set up to make it likely that the vector will change between when the index is checked against the size of the vector and when the element is gotten from the vector.
Here is some smaple output. The error will occur in different places on different runs, but it will usually appear somewhere:
java Vector3 Vector had size 0 Vector has size 0 Vector had size 14 0 :abcdef40 1 :abcdef45 2 :abcdef49 3 :abcdef57 4 :abcdef63 5 :abcdef70 6 :abcdef75 7 :abcdef82 8 :abcdef88 9 :abcdef94 10 :abcdef102 11 :abcdef109 12 :abcdef113 13 :abcdef119 14 :abcdef126 15 :abcdef135 16 :abcdef149 17 :abcdef155 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 18 >= 18 at java.lang.Throwable.fillInStackTrace(Native Method) at java.lang.Throwable.(Throwable.java:94) at java.lang.Exception. (Exception.java:42) at java.lang.RuntimeException. (RuntimeException.java:47) at java.lang.IndexOutOfBoundsException. (IndexOutOfBoundsException.java:44) at java.lang.ArrayIndexOutOfBoundsException. (ArrayIndexOutOfBoundsException.java:53) at java.util.Vector.elementAt(Compiled Code) at Vector3.showVector(Compiled Code) at Vector3.main(Compiled Code)
An Enumeration is an interface with two methods:
class Vector4 { public static void showVector(Vector v) { String str; Enumeration enum; enum = v.elements(); while (enum.hasMoreElements()) { try { Thread.sleep(100); } catch (InterruptedException e) {} str = (String)enum.nextElement(); System.out.println(str); } } ...We can run this and see if it has the same problem.
The vector documentation says:
class Vector4c { public static void showVector(Vector v) { String str; Enumeration enum; enum = v.elements(); while (enum.hasMoreElements()) { try { Thread.sleep(100); } catch (InterruptedException e) {} try { str = (String)enum.nextElement(); } catch (NoSuchElementException e) { System.out.println("Could not find element"); return; } System.out.println(str); } } ...We can run this and see what happens. Here is some smaple output:
java Vector4c Vector had size 1 Vector has size 0 Vector had size 4 Could not find element Vector has size 0 Vector had size 1 abcdef111 abcdef118 Vector has size 2 Vector had size 5 abcdef164 abcdef169 abcdef174 abcdef180 abcdef187 abcdef196 abcdef206 abcdef210 abcdef215 abcdef227 Could not find element Vector has size 9 Vector had size 22 abcdef253 abcdef258 abcdef265 abcdef268 abcdef272 ...
Recall that each object has its own monitor.
Usually, to protect a piece of code you use the object which contains that code.
Here the code is in two different objects.
We can use the monitor corresponding to the vector itself for the
synchronization.
import java.util.*; import java.io.*; class Vector4S { public static void showVector(Vector v) { String str; Enumeration enum; synchronized(v) { enum = v.elements(); while (enum.hasMoreElements()) { try { Thread.sleep(100); } catch (InterruptedException e) {} str = (String)enum.nextElement(); System.out.println(str); } } } public static void main(String args[]) { Vector v; BusyThreadS t; v = new Vector(); t = new BusyThreadS(v,1000); t.start(); for (int i=0;i < 10;i++) { System.out.println("Vector had size "+v.size()); showVector(v); System.out.println("Vector has size "+v.size()); try { Thread.sleep(1000); } catch (InterruptedException e) {} } } } import java.util.*; class BusyThreadS extends Thread { Vector v; int count; public BusyThreadS(Vector v, int count) { this.v = v; this.count = count; } public void run() { double ran; for (int i=0;i < count;i++) { ran = Math.random(); synchronized(v) { if (ran > 0.5) v.addElement("abcdef"+i); else if (v.size() > 0) v.removeElementAt(0); } try { sleep(10); } catch (InterruptedException e) {} } } }
If you watch Vector4S run carefully, you will see that it does not
terminate immediately when it is done printing.
It is waiting for the BusyThreadS thread to exit.
You can make it exit immediately by having the thread run as a daemon:
t = new BusyThreadS(v,1000); t.setDaemon(true); t.start();This code is in Vector4Sd.java.
The Java Virtual Machine terminates when the only threads running are
daemon threads.
You can set a thread to be a daemon thread (rather than a user thread)
before it starts running.