《算法》环境搭建中的问题,用 cmd 和 IntelliJ Idea 分别编译和运行 Java 程序

▶ 尝试运行了书中的一个代码(二分搜索与白名单),发现环境配置过程中有很多问题,姑且先把成功了的过程写在这里,仅供参考。

● 工作目录为 "testJava",文件目录如下,IntelliJ Idea 中建立了包 package01 和其中的一个类 class01.java,源文件放在其中(原始代码如下,大意是输入白名单文件和待筛查文件,输出白名单中不存在的值)。自动编译生成的文件是 class01.class。输入白名单数据 tinyW.txt,待筛查文件 tinyT.txt。

D:\CODE\JAVA\TESTJAVA
│  testJava.iml
│  
├─.idea
│      misc.xml
│      modules.xml
│      workspace.xml
│      
├─out
│  └─production
│      └─testJava
│          └─package01
│                  class01.class
│                  
└─src
    └─package01
            class01.java
 1 package package01;
 2 
 3 import java.util.Arrays;
 4 
 5 import edu.princeton.cs.algs4.StdIn;
 6 import edu.princeton.cs.algs4.StdOut;
 7 import edu.princeton.cs.algs4.In;
 8 
 9 public class class01
10 {
11     private class01() {}
12 
13     public static int indexOf(int[] a, int key)
14     {
15         int lo = 0, hi = a.length - 1;
16         while (lo <= hi)
17         {
18             int mid = lo + (hi - lo) / 2;
19             if      (key < a[mid]) hi = mid - 1;
20             else if (key > a[mid]) lo = mid + 1;
21             else return mid;
22         }
23         return -1;
24     }
25 
26     @Deprecated
27     public static int rank(int key, int[] a
28     {
29         return indexOf(a, key);
30     }
31 
32     public static void main(String[] args)
33     {
34         In in = new In(args[0]);
35         int[] whitelist = in.readAllInts();
36 
37         Arrays.sort(whitelist);
38 
39         while (!StdIn.isEmpty())
40         {
41             int key = StdIn.readInt();
42             if (class01.indexOf(whitelist, key) == -1)
43                 StdOut.println(key);
44         }
45     }
46 }

● 前提工作:JDK 版本和 JRE 版本要对应(https://www.oracle.com/technetwork/java/javase/downloads/index.html),否则会出现 “能编译不能运行” 的情况,报错为 UnsupportedClassVersionError;安装教材附带的类库 algs4(https://algs4.cs.princeton.edu/code/,拖到中间一些的部分),需要管理员权限运行,他会自动下载和安装到用户目录,设置环境变量

● 使用命令行进行操作:将输入文件 tinyW.txt 和 tinyT.txt 放到 src 目录下,如图所示。这里有若干可以说的事情:

   ① 设置环境变量 CLASSPATH 为 algs4.jar 的绝对路径,可以在我的电脑的属性里添加,也可以在命令行里临时添加,还可以在 javac 命令中以选项的方式添加;有说法认为需要附上当前目录 ".",但是我测试中没有加也可以。如果不添加,则编译报错 "程序包edu.princeton.cs.algs4不存在" 以及后续的 "找不到符号"(程序用到了 algs4 中的 In,StdIn,StdOut)

D:\Code\Java\testJava\src\package01>javac class01.java      // 不添加环境变变量的编译
class01.java:5: 错误: 程序包edu.princeton.cs.algs4不存在
import edu.princeton.cs.algs4.StdIn;
                             ^
class01.java:6: 错误: 程序包edu.princeton.cs.algs4不存在
import edu.princeton.cs.algs4.StdOut;
                             ^
class01.java:7: 错误: 程序包edu.princeton.cs.algs4不存在
import edu.princeton.cs.algs4.In;
                             ^
class01.java:34: 错误: 找不到符号
        In in = new In(args[0]);
        ^
  符号:   类 In
  位置: 类 class01
class01.java:34: 错误: 找不到符号
        In in = new In(args[0]);
                    ^
  符号:   类 In
  位置: 类 class01
class01.java:39: 错误: 找不到符号
        while (!StdIn.isEmpty())
                ^
  符号:   变量 StdIn
  位置: 类 class01
class01.java:41: 错误: 找不到符号
            int key = StdIn.readInt();
                      ^
  符号:   变量 StdIn
  位置: 类 class01
class01.java:43: 错误: 找不到符号
                StdOut.println(key);
                ^
  符号:   变量 StdOut
  位置: 类 class01
8 个错误

  ② 代码首行写了包名,运行时需要退到含有完整包名那一层目录再运行。实测代码中不加包名(把源代码第一行注释掉)仍能正确编译,但是运行时会出现下面的效果,总之都无法加载主类(注意是两种错误)。

D:\Code\Java\testJava\src\package01>java class01.class tinyW.txt < tinyT.txt            // 内层无包名运行
错误: 找不到或无法加载主类 class01.class
原因: java.lang.ClassNotFoundException: class01.class

D:\Code\Java\testJava\src\package01>java package01.class01.class tinyW.txt < tinyT.txt  // 内存有包名运行
错误: 找不到或无法加载主类 package01.class01.class
原因: java.lang.ClassNotFoundException: package01.class01.class

D:\Code\Java\testJava\src\package01>cd ..

D:\Code\Java\testJava\src>java class01 tinyW.txt < tinyT.txt                            // 外层无包名运行
错误: 找不到或无法加载主类 class01
原因: java.lang.ClassNotFoundException: class01

D:\Code\Java\testJava\src>java package01.class01 tinyW.txt < tinyT.txt                  // 外层有包名运行
错误: 找不到或无法加载主类 package01.class01
原因: java.lang.NoClassDefFoundError: class01 (wrong name: package01/class01)

  ③ 使用重定向将输入文件喂给程序,输出了正确的结果,这里没有太大问题,与后面 Idea 中作对比

● Idea 中先准备库路径(类似添加环境变量):File → Project Structure → Modules → 右边的 "+" → JARs or directories → 选择上面安装的 algs4.jar(C:\User\Username\algs4\algs4.jar)→ 左边 □ 不清楚是否要勾上,右边的 Compile / Run / Test / Provided 不清楚要选哪个,姑且选了 compile。

● 点击原谅锤编译,生成字节码文件在 out 目录下,缺少库则会报错,缺少包名仍能正确编译。

● 设置运行时配置(原谅锤右边的框)如下图。写了主类(好像必填),输入参数(程序要求,喂进去两个文件),工作目录,类路径,其他没有改动。

● 至此,程序能够正常开始运行,但还有点问题。

  ① 直接运行会发现程序会卡在 while (!StdIn.isEmpty()) 。理由是此时 Std 中内容不明,反正找不到可以作为输入结束的字符,所以会一直挂住。用 step into 去看会进入 StdIn.java ,如下所示,卡在 return 这一行上。有人说需要运行时手动补充结尾符 "^D" 或 "^Z",但是这样一来会是程序直接结束(跳过 while 循环),没有解决问题。

 1 public final class StdIn
 2 {
 3     ...
 4     
 5     public static boolean isEmpty()
 6     {
 7         return !scanner.hasNext();
 8     }
 9 
10     ...
11 }

  ② 源代码使用运行参数是 "tinyW.txt < tinyT.txt",我尝试让他打印输入参数,发现是 arg[0] = "tinyW.txt";arg[1] = "<";arg[2] = "tinyT.txt",把重定向参数当成普通函数参数了,显然是不能正确完成任务的

  ③ 最后我把代码改成如下所示(不耐烦用 StdIn 和重定向输入,而是手工读取和检测边界),运行参数为 "tinyW.txt tinyT.txt",能够正确输出结果

 1 package package01;
 2 
 3 import java.util.Arrays;
 4 
 5 import edu.princeton.cs.algs4.StdOut;
 6 import edu.princeton.cs.algs4.In;
 7 
 8 public class class01
 9 {
10     private class01() {}
11 
12     public static int indexOf(int[] a, int key)
13     {
14         int lo = 0, hi = a.length - 1;
15         while (lo <= hi)
16         {
17             int mid = lo + (hi - lo) / 2;
18             if      (key < a[mid]) hi = mid - 1;
19             else if (key > a[mid]) lo = mid + 1;
20             else return mid;
21         }
22         return -1;
23     }
24 
25     @Deprecated
26     public static int rank(int key, int[] a)
27     {
28         return indexOf(a, key);
29     }
30 
31     public static void main(String[] args)
32     {
33         In in = new In(args[0]);
34         In in2 = new In(args[1]);
35 
36         int[] whitelist = in.readAllInts();
37         int[] test = in2.readAllInts();
38 
39         Arrays.sort(whitelist);
40         Arrays.sort(test);
41         
42         for(int i=0;i<test.length;i++)
43         {
44             int key = test[i];
45             if (class01.indexOf(whitelist, key) == -1)
46                 StdOut.println(key);
47         }
48     }
49 }

▶ 未完待续:补一堆链接,包括 CSDN 和 stackoverflow 上对于这个问题的解释和方法

猜你喜欢

转载自www.cnblogs.com/cuancuancuanhao/p/9721668.html