V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yoloMiss
V2EX  ›  Java

大哥们,给菜鸟想想办法吧,求求了。

  •  
  •   yoloMiss · 2023-11-05 20:11:38 +08:00 · 4050 次点击
    这是一个创建于 394 天前的主题,其中的信息可能已经有所发展或是发生改变。
    问题是这个样子的:
    自己写的一个 springboot 程序,接受其他业务系统的数据,60m ,但是由于一些要求数据中的某些字段要求被移除,这里我就非常“合理”的将数据转成 jsonobject ,然后再通过 new jsonarray 逐步获取里面的每一条数据,然后这个时候就又非常“合理”的 oom 了。
    大概示例就是下面这个样子:
    httpReponse res = httpUtil.get(url);
    String resStr = res.getBody();
    JSONArray arrayData = JSONArray.parse(resStr);
    for(int i=0,i<arrayData.size,i++){
    JSONObject jsonData = arrayData.getJSONObject(i);
    if(jsonData.contains("key")){
    jsonData.remove(i)
    }
    }
    目前使用的 json 工具是 fastjson ,有没有希望通过升级版本解决这个问题?或者其他方案呢?
    至于怎么排查 oom 的位置,这个不太好弄(不是我不会!是一些原因限制目前只能看着代码猜测,一点一点试),也不能贴报错的图。
    19 条回复    2023-11-06 16:36:17 +08:00
    blankmiss
        1
    blankmiss  
       2023-11-05 20:17:05 +08:00   ❤️ 4
    等一下 我含根内存条 用大脑运算一下这段程序
    yoloMiss
        2
    yoloMiss  
    OP
       2023-11-05 20:23:08 +08:00
    @blankmiss 哈哈哈,扩内存当然可以。但是吧,不是那么的让感觉优雅。
    blankmiss
        3
    blankmiss  
       2023-11-05 20:23:31 +08:00
    看来你没懂我的意思
    yoloMiss
        4
    yoloMiss  
    OP
       2023-11-05 20:25:26 +08:00
    @blankmiss 讲讲!分享一下你的方案。
    lizardll
        5
    lizardll  
       2023-11-05 20:30:06 +08:00 via iPhone
    这段代码中有几个明显的问题:

    1. **循环变量语法错误**:
    ```java
    for(int i=0,i<arrayData.size,i++)
    ```
    应该修改为:
    ```java
    for(int i=0; i<arrayData.size(); i++)
    ```

    2. **删除 JSONArray 中的元素问题**: 当你从`JSONArray`中删除元素时,该数组的大小会改变,这可能会导致你错过某些元素或者遇到`IndexOutOfBoundsException`。一种解决方法是反向遍历这个数组。

    3. **`JSONObject.contains`**:
    根据我的最后的知识,`JSONObject`并没有`contains`方法。如果你想检查一个`JSONObject`是否包含某个 key ,你应该使用`has`方法:
    ```java
    if(jsonData.has("key"))
    ```

    4. **丢失分号**:
    ```java
    jsonData.remove(i)
    ```
    应该有一个分号:
    ```java
    jsonData.remove(i);
    ```

    5. **删除元素的方法不正确**:
    使用`jsonData.remove(i)`是错误的。这将试图从`JSONObject`中删除键为`i`的项,而不是从`JSONArray`中删除索引为`i`的项。你应该在`arrayData`上调用`remove`方法,如`arrayData.remove(i)`。

    考虑上述问题,修改后的代码如下:

    ```java
    httpReponse res = httpUtil.get(url);
    String resStr = res.getBody();
    JSONArray arrayData = JSONArray.parse(resStr);
    for(int i = arrayData.size() - 1; i >= 0; i--) {
    JSONObject jsonData = arrayData.getJSONObject(i);
    if(jsonData.has("key")) {
    arrayData.remove(i);
    }
    }
    ```

    请确保你的代码环境中的库方法与我的建议相匹配,不同的库可能有不同的方法名称和功能。
    lizardll
        6
    lizardll  
       2023-11-05 20:30:24 +08:00 via iPhone
    这不是问问 gpt 就能解决
    lizardll
        7
    lizardll  
       2023-11-05 20:31:53 +08:00 via iPhone
    httpReponse res = httpUtil.get(url);
    String resStr = res.getBody();
    JSONArray arrayData = JSONArray.parse(resStr);
    我是建议你用迭代器写

    Iterator<Object> it = arrayData.iterator();
    while (it.hasNext()) {
    JSONObject jsonData = (JSONObject) it.next();
    if (jsonData.has("key")) {
    it.remove();
    }
    }
    knightdf
        8
    knightdf  
       2023-11-05 20:35:10 +08:00
    chunk
    guyeu
        9
    guyeu  
       2023-11-05 21:53:29 +08:00 via iPhone
    gpt 弄混了不同的 json 库,JSONObject 当然有 contains 方法,它实现了 Map 接口。你这里明显的问题是在遍历的时候删除元素,JSONObject 内部的实现不可预期,所以有可能是这块的问题。
    stinkytofu
        10
    stinkytofu  
       2023-11-05 22:36:12 +08:00
    60M 的 JSON 再转 java 对象处理起来太消耗性能了, 建议用纯文本的方式处理, 只是移出特定的字段, 正则表达式很好写
    silentsky
        11
    silentsky  
       2023-11-06 01:16:51 +08:00 via Android
    楼上说的对 别转 JSON 对象了 直接处理字符串
    skydiver
        12
    skydiver  
       2023-11-06 01:22:41 +08:00
    @lizardll 没记错的话这个网站禁止贴 ChatGPT 生成的内容
    blankmiss
        13
    blankmiss  
       2023-11-06 08:19:38 +08:00
    @lizardll 被站长看到会 ban 号
    chuck1in
        14
    chuck1in  
       2023-11-06 09:06:06 +08:00
    op 为啥这么着急
    BQsummer
        15
    BQsummer  
       2023-11-06 10:20:31 +08:00
    试试 Gson 吧, 支持流式读取:
    JsonReader reader = new JsonReader(new InputStreamReader(inputStream));
    reader.beginArray();
    missya
        16
    missya  
       2023-11-06 11:32:53 +08:00
    fastjson 也支持流式读取吧,比一次性加载全量数据到内存中
    lff0305
        17
    lff0305  
       2023-11-06 13:04:34 +08:00
    把这个 json array 存储到 elastic search 里面,使用 elastic search 的运算符进行过滤,更新,最后导出
    knva
        18
    knva  
       2023-11-06 14:02:53 +08:00
    流式读取,直接处理字符串
    lDqe4OE6iOEUQNM7
        19
    lDqe4OE6iOEUQNM7  
       2023-11-06 16:36:17 +08:00
    httpResponse res = httpUtil.get(url);
    String resStr = res.getBody();
    JSONArray arrayData = JSONArray.parseArray(resStr);
    for (int i = 0; i < arrayData.size(); i++) {
    JSONObject jsonData = arrayData.getJSONObject(i);
    if (jsonData.containsKey("key")) {
    jsonData.remove("key");
    }
    }
    流式 API 处理 JSON ,这样:



    httpResponse res = httpUtil.get(url);
    String resStr = res.getBody();
    JSONReader reader = new JSONReader(new StringReader(resStr));
    reader.startArray();
    while (reader.hasNext()) {
    JSONObject jsonData = reader.readObject();
    jsonData.remove("key");
    // 处理 jsonData
    }
    reader.endArray();
    reader.close();
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1210 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 18:17 · PVG 02:17 · LAX 10:17 · JFK 13:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.