请在 2024 年 Clojure 调查问卷 中分享您的想法!

欢迎!有关如何工作的更多信息,请参阅关于 页面。

0
Java 交互

你好 --

我正在学习 Clojure 以及其 Java 交互功能。我正在尝试模拟这个函数

 public String readAllCharsOneByOne(BufferedReader bufferedReader) throws IOException {
    StringBuilder content = new StringBuilder();
       
    int value;
    while ((value = bufferedReader.read()) != -1) {
        content.append((char) value);
    }
       
    return content.toString();
}

到目前为止,我已经能够推理出我需要的部分

(def myfile "/path/to/svenska_sample.txt")
(import java.io.BufferedReader)
(import java.io.FileReader)
(import java.lang.StringBuilder)
(import java.lang.Character)
 
(def a-FileReader (FileReader. myfile))
(def bufferedReader (BufferedReader. a-FileReader))
(def content (StringBuilder.))

这是有效的

user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDe"]
user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDen"]
user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDen "]
user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDen t"]
user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDen ty"]
user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDen typ"]
user> (.append content (Character/toChars (.read bufferedReader)))
#object[java.lang.StringBuilder 0x490447d0 "\nDen typi"]

文件是一个小的文本文件,在 Linux 中以 UTF-8 编码,其内容如下

❯ cat svenska_sample.txt

典型的冲动型事故鸟是一群二十多的年轻人,他们经常出车祸,还经常嘴硬,至少在他们和朋友们在一起的时候。对他们来说,不幸运几乎成了他们的生活方式,他们经常发生大小不一的事故。我们称他们为事故鸟。究竟有多少个,谁也无法确切地说,因为对这个群体的定义并没有具体的说法,也没有明确的界定。但毫无疑问的是,无论是在医院的急诊室,还是在保险业,都存在着这样的人。

我编写了一个函数,使用我全新的 Clojure Java 交互技巧,看起来像这样

;; COMPILES  - BUT CAN'T GET AROUND THE 0XFFFFFFF BUG
(defn pt%% [file]
   (let [afr (FileReader. file); instances of FileReader, BufferedReader, StringBuffer
         bfr (BufferedReader. afr)
         ct (StringBuilder.)
         val (.read bfr)
         this-list (list afr bfr ct)]
         ; (apply println this-list)
         (loop []
               (when (not (= val -1))
                 (.append ct (Character/toChars (.read bfr))))
               (recur))
                ; when finished...
         (.toString ct)))
     

但是它报错了下面的错误

user> (pt%% myfile)
Execution error (IllegalArgumentException) at java.lang.Character/toChars (Character.java:8572).
Not a valid Unicode code point: 0xFFFFFFFF

究竟是什么导致了这个问题(注意:我不是 Java 程序员)?
以下是文件文本的十六进制转储

❯ cat svenska_sample.hexdump

00000000: 0a44 656e 2074 7970 6973 6b61 2069 6d70  .Den typiska imp
00000010: 756c 7369 7661 206f 6c79 636b 7366 c3a5  ulsiva olycksf..
00000020: 6765 6c6e 20c3 a472 2065 6e20 756e 6720  geln ..r en ung
00000030: 6d61 6e20 736f 6d20 6b72 6173 6368 6172  man som kraschar
00000040: 2066 6c65 7261 2062 696c 6172 2c20 6f63   flera bilar, oc
00000050: 6820 6f66 7461 2073 6b72 7974 6572 206c  h ofta skryter l
00000060: 6974 6520 6d65 6420 6465 742c 2069 2076  ite med det, i v
00000070: 6172 6a65 2066 616c 6c20 6ec3 a472 2068  arje fall n..r h
00000080: 616e 20c3 a472 2074 696c 6c73 616d 6d61  an ..r tillsamma
00000090: 6e73 206d 6564 2073 696e 6120 76c3 a46e  ns med sina v..n
000000a0: 6e65 722e 5f2e 2046 c3b6 7220 6465 6d20  ner._. F..r dem
000000b0: 6861 7220 6f74 7572 2069 2064 6574 206e  har otur i det n
000000c0: c3a4 726d 6173 7465 2062 6c69 7669 7420  ..rmaste blivit
000000d0: 656e 206c 6976 7373 7469 6c2c 206f 6368  en livsstil, och
000000e0: 2064 6520 72c3 a56b 6172 206b 6f6e 7374   de r..kar konst
000000f0: 616e 7420 7574 2066 c3b6 7220 6f6c 7963  ant ut f..r olyc
00000100: 6b6f 722c 2073 746f 7261 2073 6f6d 2073  kor, stora som s
00000110: 6dc3 a52e 204f 6c79 636b 7366 c3a5 676c  m... Olycksf..gl
00000120: 6172 206b 616c 6c61 7220 7669 2064 656d  ar kallar vi dem
00000130: 2e20 4875 7220 6dc3 a56e 6761 2064 6574  . Hur m..nga det
00000140: 2066 696e 6e73 206b 616e 2069 6e67 656e   finns kan ingen
00000150: 206d 6564 2073 c3a4 6b65 7268 6574 2073   med s..kerhet s
00000160: c3a4 6761 2c20 66c3 b672 2064 6574 2066  ..ga, f..r det f
00000170: 696e 6e73 2069 6e67 6120 6b6f 6e6b 7265  inns inga konkre
00000180: 7461 2064 6566 696e 6974 696f 6e65 7220  ta definitioner
00000190: 70c3 a520 6465 6e6e 6120 6772 7570 702c  p.. denna grupp,
000001a0: 206f 6368 2068 656c 6c65 7220 696e 6765   och heller inge
000001b0: 6e20 6769 7665 6e20 6176 6772 c3a4 6e73  n given avgr..ns
000001c0: 6e69 6e67 2061 7620 6465 6e2e 2041 7474  ning av den. Att
000001d0: 2064 6520 6669 6e6e 732c 2072 c3a5 6465   de finns, r..de
000001e0: 7220 6465 7420 656d 656c 6c65 7274 6964  r det emellertid
000001f0: 2069 6e67 656e 2074 7665 6b61 6e20 6f6d   ingen tvekan om
00000200: 2c20 7661 726b 656e 2070 c3a5 2073 6a75  , varken p.. sju
00000210: 6b68 7573 656e 7320 616b 7574 6d6f 7474  khusens akutmott
00000220: 6167 6e69 6e67 6172 2065 6c6c 6572 2069  agningar eller i
00000230: 2066 c3b6 7273 c3a4 6b72 696e 6773 6272   f..rs..kringsbr
00000240: 616e 7363 6865 6e0a                      anschen.

然后我修改了代码(见下文),因为有人建议问题可能是我使用 recur 的方式。

现在它抱怨之前一直在工作中的形式“(.append 等..”)现在不行了,并且同样的错误仍然存在。

user> (pt5 myfile)

Execution error (IllegalArgumentException) at java.lang.Character/toChars (Character.java:8572).
Not a valid Unicode code point: 0xFFFFFFFF

(defn pt5 [file]

   (let [afr (FileReader. file); instances of FileReader, BufferedReader, StringBuffer
         bfr (BufferedReader. afr)
         ct (StringBuilder.)
         this-list (list afr bfr ct)]
         ; (apply println this-list)
         (loop [val (.read bfr)]
               (when (not (= val -1))
                 (.append ct (Character/toChars (.read bfr))))
               (recur val))
                ; when finished...
                (.toString ct)))

比最初想象的要困难...
任何帮助都将非常感激。
-- Hank

1 答案

0

如果您喜欢交互式聊天来提问,Clojurians Slack社区中的 #beginners 频道(https://clojurians.slack.com)是此类问题的好去处。无论在这里还是那里,如果您愿意在公共平台如Github.com上发表您正在工作的更长的代码样本,这将非常有帮助。

关于您的问题,您的第一个函数 pt%% 在循环开始之前为 val 赋值,然后从那个点开始,val 始终保持相同的值,从不改变。因此,无论循环内部执行什么操作,它都将是无限循环,除非发生异常,这也就是您的情况。由于无限循环的问题以及 val 永远不会改变,我没有尝试诊断为什么会产生那个特定的异常。

pt5 存在相同的问题,因为 (recur val) 发生在 val 绑定到与循环开始时相同的值的上下文中。

pt5 中,尝试使用 val 作为 tocChars 方法的一个参数,并将 recur 表达式改为 (recur (.read bfr)),看看结果如何。并思考为什么它与您的问题中的版本表现不同。

谢谢。Google Clojure Group上有更长的讨论。
...