你的位置:首页 > Java教程

[Java教程]Java版本:识别Json字符串并分隔成Map集合


前言:

最近又看了点Java的知识,于是想着把CYQ.Data V5迁移到Java版本。

过程发现坑很多,理论上看大部分很相似,实践上代码写起来发现大部分都要重新思考方案。

遇到的C#转Java的一些小问题:

1:C#的ref:这个参数的主要意图是:

就算方法内部重新对参数重新(new)赋值,也能保证外部的参数指向新的值。

Java木有了,不知道新的方案是什么?还是说只能避免方法内部重新(new)赋值?

2:C#的out:这个参数的主要意图是:

处理多值返回的问题。

Java木有了,只能改返回数组了。

3:C#的SqlDbType和DbType

其实我也没想过C#为什么还要搞个DbType(用在DbParameter参数上使用)

Java:涉入不深,不知道用啥代替?

4:C#的DBNull.Value

Java:好像木有这东东,用啥代替?

5:C#的ChangeType 通用类型转换

Java:涉入不深,不知道用啥代替?

6:C#的反射Type有属性可以识别是否泛型(IsGenericType)和Nullable.GetUnderlyingType(t)

Java:在Class里找不到泛型判断,替代方案是?

7:发现Map集合的大多数默认都对key进行了排序,最后发现只有这个才默认没排序:LinkedHashMap

8:关于代码折叠:

C#里用#region和#endregion。

Java里要下个插件,然后改成//region和//endregion。

9:Java木有Internal修饰符,木有Jar包内使用的修饰符,真心不友好。

10:其它的主是一些大小写和方法的改了。

好了,先小小总结到这里,下面上Java代码,主要有3个类:

1:实现代码(内部实现类):CharState

package cyq.data.tool;/// <summary>/// 字符状态/// </summary>class CharState{  boolean jsonStart = false;//以 "{"开始了...  boolean setDicValue = false;// 可以设置字典值了。  boolean escapeChar = false;//以"\"转义符号开始了  /// <summary>  /// 数组开始【仅第一开头才算】,值嵌套的以【childrenStart】来标识。  /// </summary>  boolean arrayStart = false;//以"[" 符号开始了  boolean childrenStart = false;//子级嵌套开始了。  /// <summary>  /// 【0 取名称中】;【1 取值中】  /// </summary>  int state = -1;  /// <summary>  /// 【-1 未初始化】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】  /// </summary>  int keyStart = -1;  /// <summary>  /// 【-1 未初始化】【0 未开始】【1 无引号开始】【2 单引号开始】【3 双引号开始】  /// </summary>  int valueStart = -1;  boolean isError = false;//是否语法错误。  void CheckIsError(char c)//只当成一级处理(因为GetLength会递归到每一个子项处理)  {    switch (c)    {      case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]        isError = jsonStart && state == 0;//重复开始错误 同时不是值处理。        break;      case '}':        isError = !jsonStart || (keyStart > -1 && state == 0);//重复结束错误 或者 提前结束。        break;      case '[':        isError = arrayStart && state == 0;//重复开始错误        break;      case ']':        isError = !arrayStart;//重复开始错误        break;      case '"':      case '\'':        isError = !jsonStart;//未开始Json        break;      case ':':        isError = !jsonStart || (jsonStart && keyStart < 2 && valueStart < 2 && state == 1);//未开始Json 同时 只能处理在取值之前。        break;      case ',':        isError = (!jsonStart && !arrayStart) || (jsonStart && keyStart < 2 && valueStart < 2 && state == 0);//未开始Json 同时 只能处理在取值之后。        break;      default: //值开头。。        isError = !jsonStart || (keyStart == 0 && valueStart == 0 && state == 0);//        break;    }    //if (isError)    //{    //}  }}

 

2:实现代码(内部实现类):JsonSplit

PS:Log这个类的代码可以先注释屏蔽。

package cyq.data.tool;import java.util.*;import cyq.data.Log;public class JsonSplit{  public static boolean IsJson(String json)  {    return IsJsonAndBackIndex(json)==-1;  }  public static int IsJsonAndBackIndex(String json)  {    if(json==null || json.isEmpty() || json.length()==1)    {      return 0;          }        if ((json.charAt(0) == '{' && json.charAt(json.length() - 1) == '}') ||      (json.charAt(0)== '[' && json.charAt(json.length() - 1)== ']'))    {      int errIndex = 0;      CharState cs = new CharState();      char c;      for (int i = 0; i < json.length(); i++)      {        c = json.charAt(i);        if (SetCharState(c, cs) && cs.childrenStart)//设置关键符号状态。        {          String item = json.substring(i);          int[] v=GetValueLength(item, true);          int length = v[0];          int err=v[1];          cs.childrenStart = false;          if (err > 0)          {            errIndex = i + err;            return errIndex;          }          i = i + length - 1;        }        if (cs.isError)        {          errIndex = i;          return errIndex;        }      }      if( !cs.arrayStart && !cs.jsonStart)      {        return -1;      }      return errIndex;    }    else    {      return 0;    }  }  static List<LinkedHashMap<String, String>> Split(String json)  {    List<LinkedHashMap<String, String>> result = new ArrayList<LinkedHashMap<String, String>>();    if (json!=null && !json.isEmpty())    {      LinkedHashMap<String, String> dic = new LinkedHashMap<String, String>();      String key = "";      StringBuilder value = new StringBuilder();      CharState cs = new CharState();      try      {        //region 核心逻辑        char c;        for (int i = 0; i < json.length(); i++)        {          c = json.charAt(i);          if (!SetCharState(c, cs))//设置关键符号状态。          {            if (cs.jsonStart)//Json进行中。。。            {              if (cs.keyStart > 0)              {                key += c;              }              else if (cs.valueStart > 0)              {                value.append(c);                //value += c;              }            }            else if (!cs.arrayStart)//json结束,又不是数组,则退出。            {              break;            }          }          else if (cs.childrenStart)//正常字符,值状态下。          {            String item = json.substring(i);            int[] v= GetValueLength(item, false);            int length =v[0];            //int temp=v[1];            //value = item.SubString(0, length);            value.setLength(0);            value.append(item.substring(0, length));            cs.childrenStart = false;            cs.valueStart = 0;            //cs.state = 0;            cs.setDicValue = true;            i = i + length - 1;          }          if (cs.setDicValue)//设置键值对。          {            if (key!=null && !key.isEmpty() && !dic.containsKey(key))            {              //if (value != String.Empty)              //{              boolean isNull = json.charAt(i - 5) == ':' && json.charAt(i) != '"' && value.length() == 4 && value.toString() == "null";              if (isNull)              {                value.setLength(0);              }              dic.put(key, value.toString());              //}            }            cs.setDicValue = false;            key = "";            value.setLength(0);          }          if (!cs.jsonStart && dic.size() > 0)          {            result.add(dic);            if (cs.arrayStart)//处理数组。            {              dic = new LinkedHashMap<String, String>();            }          }        }        //endregion           }      catch (Exception err)      {        Log.WriteLogToTxt(err);      }      finally      {        key = null;        value.setLength(0);        value = null;      }    }    return result;  }  /// <summary>  /// 获取值的长度(当Json值嵌套以"{"或"["开头时)  /// </summary>  private static int[] GetValueLength(String json, boolean breakOnErr)  {        int errIndex = 0;    int len = 0;    if (json!=null && !json.isEmpty())    {      CharState cs = new CharState();      char c;      for (int i = 0; i < json.length(); i++)      {        c = json.charAt(i);        if (!SetCharState(c, cs))//设置关键符号状态。        {          if (!cs.jsonStart && !cs.arrayStart)//json结束,又不是数组,则退出。          {            break;          }        }        else if (cs.childrenStart)//正常字符,值状态下。        {          int[] v=GetValueLength(json.substring(i), breakOnErr);//递归子值,返回一个长度。。。          int length = v[0];          errIndex=v[1];          cs.childrenStart = false;          cs.valueStart = 0;          //cs.state = 0;          i = i + length - 1;        }        if (breakOnErr && cs.isError)        {          errIndex = i;          break;        }        if (!cs.jsonStart && !cs.arrayStart)//记录当前结束位置。        {          len = i + 1;//长度比索引+1          break;        }      }    }    int[] valueAndErrIndex=new int[2];    valueAndErrIndex[0]=len;    valueAndErrIndex[1]=errIndex;    return valueAndErrIndex;  }    /// <summary>  /// 设置字符状态(返回true则为关键词,返回false则当为普通字符处理)  /// </summary>  private static boolean SetCharState(char c, CharState cs)  {    switch (c)    {      case '{'://[{ "[{A}]":[{"[{B}]":3,"m":"C"}]}]        if (cs.keyStart <= 0 && cs.valueStart <= 0)        {          cs.CheckIsError(c);          if (cs.jsonStart && cs.state == 1)          {            cs.valueStart = 0;            cs.childrenStart = true;          }          else          {            cs.state = 0;          }          cs.jsonStart = true;//开始。          return true;        }        break;      case '}':        if (cs.keyStart <= 0 && cs.valueStart < 2)        {          cs.CheckIsError(c);          if (cs.jsonStart)          {            cs.jsonStart = false;//正常结束。            cs.valueStart = 0;            cs.setDicValue = true;          }          return true;        }        // cs.isError = !cs.jsonStart && cs.state == 0;        break;      case '[':              if (!cs.jsonStart)        {          cs.CheckIsError(c);          cs.arrayStart = true;          return true;        }        else if (cs.jsonStart && cs.state == 1 && cs.valueStart < 2)        {          cs.CheckIsError(c);          //cs.valueStart = 1;          cs.childrenStart = true;          return true;        }             break;      case ']':             if (!cs.jsonStart && cs.keyStart <= 0 && cs.valueStart <= 0)        {          cs.CheckIsError(c);          if (cs.arrayStart)// && !cs.childrenStart          {            cs.arrayStart = false;          }          return true;        }            break;      case '"':      case '\'':        cs.CheckIsError(c);              if (cs.jsonStart)        {          if (cs.state == 0)//key阶段          {            cs.keyStart = (cs.keyStart <= 0 ? (c == '"' ? 3 : 2) : 0);            return true;          }          else if (cs.state == 1)//值阶段          {            if (cs.valueStart <= 0)            {              cs.valueStart = (c == '"' ? 3 : 2);              return true;            }            else if ((cs.valueStart == 2 && c == '\'') || (cs.valueStart == 3 && c == '"'))            {              if (!cs.escapeChar)              {                cs.valueStart = 0;                return true;              }              else              {                cs.escapeChar = false;              }            }          }        }               break;      case ':':        cs.CheckIsError(c);             if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 0)        {          cs.keyStart = 0;          cs.state = 1;          return true;        }        // cs.isError = !cs.jsonStart || (cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1);        break;      case ',':        cs.CheckIsError(c);              if (cs.jsonStart && cs.keyStart < 2 && cs.valueStart < 2 && cs.state == 1)        {          cs.state = 0;          cs.valueStart = 0;          cs.setDicValue = true;          return true;        }        else if (cs.arrayStart && !cs.jsonStart)        {          return true;        }        break;      case ' ':      case '\r':      case '\n':        if (cs.jsonStart && cs.keyStart <= 0 && cs.valueStart <= 0)        {          return true;//跳过空格。        }        break;      default: //值开头。。        cs.CheckIsError(c);        if (c == '\\') //转义符号        {          if (cs.escapeChar)          {            cs.escapeChar = false;          }          else          {            cs.escapeChar = true;            return true;          }        }        else        {          cs.escapeChar = false;        }        if (cs.jsonStart)        {          if (cs.keyStart <= 0 && cs.state <= 0)          {            cs.keyStart = 1;//无引号的          }          else if (cs.valueStart <= 0 && cs.state == 1)          {            cs.valueStart = 1;//无引号的          }        }        break;    }    return false;  }}

3:实现代码(外部调用类):JsonHelper

package cyq.data.tool;import java.util.*;public class JsonHelper {   /// <summary>  /// 检测是否Json格式的字符串  /// </summary>  /// <param name="json">要检测的字符串</param>  public static boolean IsJson(String json)  {    return JsonSplit.IsJson(json);  }   /// <summary>  /// 将Json分隔成键值对。  /// </summary>  public static Map<String, String> Split(String json)  {    List<LinkedHashMap<String, String>> result = JsonSplit.Split(json);    if (result != null && result.size() > 0)    {      return result.get(0);    }    return null;  }  /// <summary>  /// 将Json 数组分隔成多个键值对。  /// </summary>  public static List<LinkedHashMap<String, String>> SplitArray(String jsonArray)  {    if (jsonArray==null || jsonArray.isEmpty())    {      return null;    }    jsonArray = jsonArray.trim();    return JsonSplit.Split(jsonArray);  }}

 

4:实现代码(单元测试类):JsonTest

PS:标签Key没用引号,所以识别是false,但Split方法是兼容不严格模式的,所以还能分成Map。

总结:

总体而言,虽然Java很原始,C#很高级,但技术这东西,走向一个极端后,也得学学大闸蟹,得横着走。

只有两手抓,两手都硬的时候,才不会被技术所孤立。。。