再談編碼規範

我曾經發過兩篇文章阿里編碼規範如何使用Java的註釋,裏面大致介紹瞭如何寫註釋,java代碼編寫的基本的約定等等,應該算是從事IT行業或者程序員的基本要求吧。可惜的是現在從事編程的門檻越來越低了,各種野路子出身的Coder簡直逆天了。在你沒有看到別人寫的代碼之前,你從來不會想象到怎麼可以把代碼寫的這麼"臭"!

下面我會貼一份完整的代碼出來,請忽略它要實現的功能
後面我會講到一系列的約定,約定即是規範,他雖然不是法則也不是公理或定理,但是你遵守了你才能跟世界更好的溝通

源代碼:

package com.dtjx.controller.subWay;

import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import redis.clients.jedis.Jedis;

import com.dtjx.model.fault.Faulthistory;
import com.dtjx.model.route.Stop;
import com.dtjx.model.subWay.SubWayInfo;
import com.dtjx.model.systemset.SpecialFieldText;
import com.dtjx.model.systemset.Specialfield;
import com.dtjx.model.util.BigDataParam;
import com.dtjx.service.fault.FaulthistoryService;
import com.dtjx.service.route.StopService;
import com.dtjx.service.subWay.SubWayInfoService;
import com.dtjx.service.systemset.SpecialfieldService;
import com.dtjx.service.systemset.WebInterfaceService;
import com.dtjx.util.BigDataWebServiceInterfaceUtil;
import com.dtjx.util.MethodUtil;
import com.gph.saviorframework.quartz.SpringUtils;
import com.gph.saviorframework.shiro.session.RedisManager;

/*class MyThread implements Runnable{ private Map<Integer,Object> subwayLifeCount=new HashMap<Integer,Object>(); private Jedis redis=SpringUtils.getBean(RedisManager.class).getJedis();; public MyThread() { //this.name = name; } public void run(){ for(int i=0;i<100;i++){ //System.out.println("線程開始:"+this.name+",i="+i); } }*/
public class DrivingStateMonitorThread{  
private Map<Integer,Object> subwayLifeCount=new HashMap<Integer,Object>();
private Jedis redis=SpringUtils.getBean(RedisManager.class).getJedis();
private StopService stopService=SpringUtils.getBean(StopService.class);
class subWayStatusCount{
	 private int subWayOnline;
	 private int subWayOffline;
	 private int subWayOnFault;
	public int getSubWayOnline() {
		return subWayOnline;
	}
	public void setSubWayOnline(int subWayOnline) {
		this.subWayOnline = subWayOnline;
	}
	public int getSubWayOffline() {
		return subWayOffline;
	}
	public void setSubWayOffline(int subWayOffline) {
		this.subWayOffline = subWayOffline;
	}
	public int getSubWayOnFault() {
		return subWayOnFault;
	}
	public void setSubWayOnFault(int subWayOnFault) {
		this.subWayOnFault = subWayOnFault;
	}
	 
}
public class SubWayDrivingStatus extends SubWayInfo{
	private String runningModel="--";//運行模式
	private String speed="0";//速度
	private String endStopId="1";//終點站Id
	private String nowStopId="0";//當前站Id
	private String nextStopId="1";//下一站Id
	private String endStop="--";//終點站
	private String nowStop="--";//當前站
	private String nextStop="--";//下一站
	private String driverNumber;//司機工號
	private String drivingStatus;//運行狀態 低速/高速/正常/停止
	private String faults="無故障";//列車故障
	private String updateTime;//更新時間
	private String bogieStatus="正常";//轉向架狀態
	private String workingCondition="--";//工況
	private String nextStopDistance="--";//下一站距離
	//構造函數
	public SubWayDrivingStatus(){
		
	};
    public SubWayDrivingStatus(SubWayInfo s){
    	super(s.getId(), s.getSubwayNum(), s.getSubwayCarriageNum(), 
    			s.getSubwayInfomation(), s.getCitys(),s.getCityName(), s.getRouteId(),
				s.getRouteName(), s.getSubwayStatus(), s.getIsDeleted());
	};
	public String getEndStopId() {
		return endStopId;
	}
	public void setEndStopId(String endStopId) {
		this.endStopId = endStopId;
	}
	public String getNowStopId() {
		return nowStopId;
	}
	public void setNowStopId(String nowStopId) {
		this.nowStopId = nowStopId;
	}
	public String getNextStopId() {
		return nextStopId;
	}
	public void setNextStopId(String nextStopId) {
		this.nextStopId = nextStopId;
	}
	public String getNextStopDistance() {
		return nextStopDistance;
	}
	public void setNextStopDistance(String nextStopDistance) {
		this.nextStopDistance = nextStopDistance;
	}
	public String getRunningModel() {
		return runningModel;
	}
	public String getSpeed() {
		return speed;
	}
	public void setSpeed(String speed) {
		this.speed = speed;
	}
	public void setRunningModel(String runningModel) {
		this.runningModel = runningModel;
	}
	public String getEndStop() {
		return endStop;
	}
	public String getNowStop() {
		return nowStop;
	}
	public String getNextStop() {
		return nextStop;
	}
	public String getDriverNumber() {
		return driverNumber;
	}
	public void setDriverNumber(String driverNumber) {
		this.driverNumber = driverNumber;
	}
	public String getDrivingStatus() {
		return drivingStatus;
	}
	public void setDrivingStatus(String drivingStatus) {
		this.drivingStatus = drivingStatus;
	}
	public String getFaults() {
		return faults;
	}
	public void setFaults(String faults) {
		this.faults = faults;
	}
	public String getUpdateTime() {
		return updateTime;
	}
	public void setUpdateTime(String updateTime) {
		this.updateTime = updateTime;
	}
	public String getWorkingCondition() {
		return workingCondition;
	}
	public void setWorkingCondition(String workingCondition) {
		this.workingCondition = workingCondition;
	}
	public String getBogieStatus() {
		return bogieStatus;
	}
	public void setBogieStatus(String bogieStatus) {
		this.bogieStatus = bogieStatus;
	}
}
public List getSubwayListAll()
{
	List subwayListAll =null;
	//首先判斷redis中是否是列車信息的全部列表
	String subWayInfoAll=redis.get("subWayInfo-all");
	if(subWayInfoAll == null || subWayInfoAll.trim().isEmpty())
	{
		SubWayInfoService subWayInfoService=SpringUtils.getBean(SubWayInfoService.class);
		Map<String, Object> params =new HashMap<String, Object>();
		params.put("sort", "id");
		params.put("dir", "desc");
		subwayListAll = subWayInfoService.findSubWayInfo(params);//全部的列車信息
		redis.set("subWayInfo-all", JSONArray.fromObject(subwayListAll).toString());
	}
	else
	{
		subwayListAll=JSONArray.toList(JSONArray.fromObject(subWayInfoAll),SubWayInfo.class);
		//subwayListAll=(List) JSONUtils.parse(subWayInfoAll);
	}
	return subwayListAll;
}

   /** * 獲取所有列車的形式狀態信息,並定時更新 * 邏輯:查詢數據庫中現有的車輛信息,然後根據遍歷車輛信息,取列車編號去查詢大數據端,獲取大數據端的數據, * 進行數據拼接 * 返回內容:返回的數據內容是 車輛的基本信息+大數據端的車輛行駛信息 * @return */
	public void getlist() {
		SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//System.out.println("列車行駛狀態監測啓動"+formatShow.format(new Date()));
		Integer subWayCount = 0;// 列車總量
		subWayStatusCount ssc=new subWayStatusCount();
		ssc.setSubWayOffline(0);// 離線列車的數量
		ssc.setSubWayOnFault(0);// 故障列車的數量
		ssc.setSubWayOnline(0);// 在線列車的數量
		
		try {
			SpecialfieldService specialfieldservice=SpringUtils.getBean(SpecialfieldService.class);
			WebInterfaceService webInterfaceservice=SpringUtils.getBean(WebInterfaceService.class);
			List subwayListAll =getSubwayListAll();
			String dataTime="2017010100000000";
			subWayCount = subwayListAll.size();
			/**將for循環中需要的變量提前定義,再循環體內賦值指定,不再新建,可提升性能**/
			List statusList = new ArrayList();
			Specialfield sf = new Specialfield();
			SubWayInfo m =null;
			BigDataParam bigParam=new BigDataParam();//大數據接口所需的參數
			for (int i = 0; i < subwayListAll.size(); i++) {
				m = (SubWayInfo) subwayListAll.get(i);
					if(!subwayLifeCount.containsKey(m.getId()))
					{
						Map<String,Object> indexMap=new HashMap<String,Object>();
						indexMap.put("lifeSignl", "");//生命信號
						indexMap.put("count",0);//生命信號重複的次數
						subwayLifeCount.put(m.getId(), indexMap);
					}
					SubWayDrivingStatus sds = initSubWayDrivingStatus(m);
					/*獲取大數據端接口參數*/
					bigParam.initBySubwayInfo(m);
					/*獲取特殊字段列表*/
					sf.setCitys(m.getCitys());
					sf.setRoutes(m.getRouteId());
					List<Specialfield> specialfieldList = specialfieldservice.get(sf);
					List<Map<String,Object>> specialfieldGroup=specialfieldservice.getSpecialfieldGroupByTrainumInterfacenum(sf);
					List<String> list=new ArrayList<String>();
					for(int j=0;j<specialfieldGroup.size();j++)
					{
						Map<String, Object> mc=specialfieldGroup.get(j);
						bigParam.setData_code(String.valueOf(mc.get("datacoding")).split(","));
						bigParam.setData_type(String.valueOf(mc.get("datatype")).split(","));
						bigParam.setImetro_car_no(String.valueOf(mc.get("trainum")));
						bigParam.setIpackage(mc.get("interfacenum").toString());
						//list.addAll(BigDataWebServiceInterfaceUtil.getRealTimeDataFromFile(webInterfaceservice,bigParam));
						list.addAll(BigDataWebServiceInterfaceUtil.getRealTimeData(webInterfaceservice,bigParam));
					}
					if(list.size()<=0)
					{
						sds.setSubwayStatus("離線");;
					}
					else
					{
						if(!specialfieldList.isEmpty())
						{
							Specialfield s=null;
							for (int j=0;j<specialfieldList.size();j++) {
								s=specialfieldList.get(j);
								Field field;
								String itemValue=s.getItemvalue();
								String itemName=s.getItemname();
								String dataCoding=s.getDatacoding();
								try {
									field = sds.getClass().getDeclaredField(itemValue);
									field.setAccessible(true);
									
									for(int r=0;r<list.size();r++)
									{
										String str=list.get(r);
										if (str!=null && !str.isEmpty()) {
											//field.set(sds, "0");
											JSONObject json2 = JSONObject.fromObject(str);
											for (Iterator iter = json2.keys(); iter.hasNext();) {
												String key = (String)iter.next();
												JSONObject json=JSONObject.fromObject(json2.getString(key));
												if(!json.isNullObject()&&!json.isEmpty())
												{
													if(json.containsKey("OP_TIME"))
													{
														dataTime=json.getString("OP_TIME");
													}
													if (json.containsKey(dataCoding)) {
														field.set(sds, json.get(dataCoding).toString());
														if (itemName.equalsIgnoreCase("速度")) {
															sds.setDrivingStatus(MethodUtil.subwayStatusBySpeed(Double.valueOf(json.get(dataCoding).toString())));
														}
														else if (itemName.equalsIgnoreCase("生命信號")) {
															
															String signl=json.get(dataCoding).toString();
															writeLifeMap(signl,m.getId());
														}
														else if (itemName.equalsIgnoreCase("工況")||itemName.equalsIgnoreCase("模式")) {
															String value=json.get(dataCoding).toString();
															List<SpecialFieldText> sptList = s.getShowArr();
															specialCodeShowValue(sptList,value,itemName,sds);
														}
													}
												}
												else
												{
													continue;
												}
													 
											}
									}
									}
								} catch (Exception e) {
									// TODO Auto-generated catch block
									//e.printStackTrace();
									continue;
								}
									
							}
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
						else
						{
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
					}
					
					statusList.add(sds);
			}
			redis.set("DrivingState", JSONArray.fromObject(statusList).toString());
			redis.set("DrivingState-subWayCount", subWayCount.toString());
			redis.set("DrivingState-subWayOnline", String.valueOf(ssc.getSubWayOnline()));
			redis.set("DrivingState-subWayOffline",String.valueOf(ssc.getSubWayOffline()));
			redis.set("DrivingState-subWayOnFault",String.valueOf(ssc.getSubWayOnFault()));
			if (redis != null) {
				redis.close();
	        }
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	public SubWayDrivingStatus initSubWayDrivingStatus(SubWayInfo s)
	{
		SubWayDrivingStatus sds=new SubWayDrivingStatus(s);
		return sds;
	}
	//根據生命信號的變化,對各個列車的生命信號重複的計數進行讀取和改寫
	public void writeLifeMap(String signl,Integer id)	{
		Map lifeMap=(Map) subwayLifeCount.get(id);
		if(signl.equalsIgnoreCase(lifeMap.get("lifeSignl").toString()))
		{
			int c=(int)lifeMap.get("count");
			lifeMap.put("count", c+1);												}
		else
		{
			lifeMap.put("lifeSignl",signl);
			lifeMap.put("count", 0);
		}
	
	}
	//根據生命信號的變化,對各個列車的生命信號重複的計數進行讀取和改寫
		public Integer getLifeCount(Integer id)	{
			int c=0;
			try {
				Map lifeMap=(Map) subwayLifeCount.get(id);
				c=(int)lifeMap.get("count");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			return c;
				
		
		}
	//將需要key-vaue對應的字段進行特殊的處理
	public void specialCodeShowValue(List<SpecialFieldText> sptList,String value,String itemname,SubWayDrivingStatus sds)
	{
		for (int j = 0; j < sptList.size(); j++) {
			SpecialFieldText spt = sptList.get(j);
			if (spt.getValue().equals(Integer.valueOf(value).toString())) {
				if(itemname.equalsIgnoreCase("工況"))
				{
					sds.setWorkingCondition(spt.getText());
					break;//找到了,退出當前循環
				}
				else if(itemname.equalsIgnoreCase("模式"))
				{
					sds.setRunningModel(spt.getText());
					break;//找到了,退出當前循環
					}
			}
		}
	}

/** * 根據數據時間來判定車輛是離線還是在線 * @param dataTime * @param sds * @param trainId * @param ssc */
	/** * 診斷車輛的狀態,根據是生命信號,如果生命信號連續10次都一樣,則判定爲離線,如果少於10次則爲在線 * @param count 生命信號重複的次數 * @param dataTime 數據時間 * @param sds 列車行駛狀態實體 * @param trainId 列車id * @param ssc 列車狀態 */
	public void setSubWayStatus(Integer count, String dataTime,SubWayDrivingStatus sds,
			Integer trainId, subWayStatusCount ssc) {
		SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			int subWayOnline=ssc.getSubWayOnline();
			int subWayOnFault=ssc.getSubWayOnFault();
			int subWayOffline=ssc.getSubWayOffline();
			Date date1 = format.parse(dataTime);
			if (count<10)//小於10次相同的生命信號,代表車輛還在線
			{

				sds.setSubwayStatus("在線");
				subWayOnline++;
				String faultResult = haveFault(trainId);
				sds.setFaults(faultResult);
				if (!faultResult.equals("無故障")) {
					subWayOnFault++;
					sds.setFaults("有故障");
					if(faultResult.equals("有轉向架故障"))
					{
						sds.setBogieStatus("故障");
					}
					else
					{
						sds.setBogieStatus("正常");
					}
				}

			} else {// 如果生命信號連續10次相同,則代表 本列車已經離線
					sds.setSubwayStatus("離線");
					sds.setDrivingStatus("");
					subWayOffline++;
					String faultResult = haveFault(trainId);
					sds.setFaults(faultResult);
					if (!faultResult.equals("無故障")) {
						subWayOnFault++;
						sds.setFaults("有故障");
						if(faultResult.equals("有轉向架故障"))
						{
							sds.setBogieStatus("故障");
						}
						else
						{
							sds.setBogieStatus("正常");
						}
						
					}
		
			}
			Stop stop=new Stop();
			stop=stopService.selectByActualId(sds.getEndStopId(),sds.getRouteId(),sds.getCitys());
			if(stop!=null)
			{
				sds.endStop=stop.getStopName();
			}
			else
			{
				sds.endStop="--";
			}
			stop=stopService.selectByActualId(sds.getNowStopId(),sds.getRouteId(),sds.getCitys());
			if(stop!=null)
			{
				sds.nowStop=stop.getStopName();
			}
			else
			{
				sds.nowStop="--";
			}
			stop=stopService.selectByActualId(sds.getNextStopId(),sds.getRouteId(),sds.getCitys());
			if(stop!=null)
			{
				sds.nextStop=stop.getStopName();
			}
			else
			{
				sds.nextStop="--";
			}
			stop=null;
			sds.setUpdateTime(formatShow.format(date1));
			ssc.setSubWayOffline(subWayOffline);// 離線列車的數量
			ssc.setSubWayOnFault(subWayOnFault);// 故障列車的數量
			ssc.setSubWayOnline(subWayOnline);// 在線列車的數量
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/** * 判斷是否有故障 * @param trainId * @return */
	public String haveFault(Integer trainId) {
		Faulthistory f = new Faulthistory();
		f.setTrainid(trainId.toString());
		FaulthistoryService faulthistoryservice=SpringUtils.getBean(FaulthistoryService.class);
		List<Faulthistory> list = faulthistoryservice.get(f);
		boolean flag = false;
		String result="無故障";
		for (Faulthistory ft : list) {
			if (ft.getFaultstatus().equals("1")) {
				flag = true;
				result= "有故障";
				if(ft.getSystems().equals("575"))//如果是轉向架的問題
				{
					result= "有轉向架故障";
				}
			}
		}
		faulthistoryservice=null;
		//return (flag? "有故障" : "無故障");
		return result;

	}
	public List<Map<String, Object>>  groupListByCarNo( List<Specialfield> dataList)
	{
		List<Map<String, Object>> listMapResult=new ArrayList<Map<String, Object>>();
		Specialfield dataItem=new Specialfield(); // 數據庫中查詢到的每條記錄
		Map<String, List<Specialfield>> resultMap= new HashMap<String, List<Specialfield>>(); // 最終要的結果
		for(int i=0;i<dataList.size();i++){
		    dataItem = dataList.get(i);
		    if(resultMap.containsKey(dataItem.getTrainum())){
		        resultMap.get(dataItem.getTrainum()).add(dataItem);
		    }else{
		        List<Specialfield> list = new ArrayList<Specialfield>();
		        list.add(dataItem);
		        resultMap.put(dataItem.getTrainum(),list);
		    }
		} 
		
		Iterator it=resultMap.keySet().iterator();
		while(it.hasNext())
		{
			Map<String, Object> m=new HashMap<String, Object>();
			String key=it.next().toString();
			List<Specialfield> L=resultMap.get(key);
			m.put("carNo", key);
			m.put("fields", L);
			listMapResult.add(m);
		}

		return listMapResult;
			
		}
};

上面是一個完整的類文件,然後從頭到尾分析這個類文件的編碼規範性,以及開發的基本要求。

看類文件整體

首先,作爲程序員,寫完一段代碼後,要把代碼格式化一下,並且做這一步非常簡單。目前,據我瞭解市面上所有的IDE工具,都帶有格式化功能,可以對某一段/塊代碼,某個類文件,甚至對所有類文件(整個項目)整體格式化。相信可能有某些個別‘異類’就喜歡用記事本這個編輯軟件,寫代碼就用它,即便是這樣,那你也應該手動的格式化你的代碼!這是最基本的要求!

接着看上面代碼,公司要求用eclipse開發,結果代碼寫完了,顯然沒有格式化:類和屬性,該縮進的不縮,不該縮進的縮進,變量/屬性對不齊…亂七八糟的
在這裏插入圖片描述

上面貼圖的這段代碼,遠不止圖中所說的這些問題

內部類的約定

在java中使用內部類/靜態內部類/私有靜態內部類,請遵守約定,要放到主類的最後面,或者至少要放到主類裏公開方法的後面,多閱讀一下java的原碼,大神的代碼總是需要你去借鑑的,從來沒有發現主類定義好了,緊接着定義內部類,他們總是在主類的後面

關於類的註釋

對於一個類文件(一個類文件可能包含多個類)或者一個類,在主類上必須包含類註釋,並且註釋的格式必須用如下的格式

/** * ... * / 

不允許使用 // ... 或者 /*...*/ 格式,這裏說一下原因,一個類完成後,在生成java api時候,只識別 /** ... */ 格式的註釋,不識別後面兩種註釋。

另外再說明一下,類註釋中需要說明類的主要作用,作者,版本等,可參考 javadoc註釋標籤 另外在註釋中是支持html標籤的

關於類、屬性的註釋約定

在使用publicprotected修飾的類和屬性必須提供註釋說明,並且採用/** ... */ 格式的註釋

特別是public 修飾符,在生成java api的時候是一定會對其生成api的,如果不註釋,即便生成了api,你也不知道它是做什麼的!

上面貼圖中,所有的public的方法,都沒有註釋,這是不符合規範的;圖中getter和setter方法都缺少註釋

去掉無效的註釋

雖然不寫註釋,會讓人感覺很可惡 ,但這不是最可惡的,最可惡的是對代碼理解沒有完全作用甚至還惡意誤導別人理解你得意思的註釋,這樣的註釋需要在你的代碼中堅決剔除掉!
在這裏插入圖片描述
上面這一塊代碼刪掉吧,既不是對類的註釋,讀一下,還容易誤導他人要起線程去跑什麼東西;仔細看看還跟這個類沒任何一點兒關係,這不是在浪費別人的時間嗎?

公共類請分別定義成兩個類文件,不要放到一起

在這裏插入圖片描述
沒有什麼好說的,上面貼圖主類是DrivingStateMonitorThread,緊接着有定義了一個公共類SubWayDrivingStatus,請把SubWayDrivingStatus單獨定義一個類文件,或者去掉public修飾符。

我們再看這個內部類SubWayDrivingStatus的兩個構造函數定義
在這裏插入圖片描述
寫過多年java代碼,頭一次看到這樣定義構造函數的,方法後加分號,雖然寫分號不報錯,我感覺應該給IDE打差評;分號不該寫的地方,不要隨便亂寫!

java的另一個規範用法:大括號的使用

在這裏插入圖片描述

看了上面貼圖的代碼,我的第一印象,這是個一寫C語言代碼的孩子轉來寫java的;還別說,仔細看看還挺「優美」的,用大括號結構對稱啊!

但是,java代碼有java自己的規範,首先使用大括號的結構請保持如下結構:
Eclipse裏面就有java代碼格式

java泛型的使用

接着看代碼,函數public List getSubwayListAll()的返回類型是List,而List是一個接口,代表某類數據的集合,既然是某類數據,那麼這個某類就可以代表任何數據啦,比如說,一個int數字,一個String字符串,一個Double的雙精度小數,獲取其他什麼的類型的java對象,這個List都能放的下,現在問題就有了,既然返回是這個List數據,調用這個方法getSubwayListAll()的人怎麼可能知道你到底在List裏面放的是什麼數據呢!

java泛型從jdk5就已經引入了,現在都出來jdk10了,代碼裏面還出現這麼低級的類型錯誤,這玩意的隱患太多了,請添加上泛型用於說明給調用人的是何種數據,請寫public List<SubWayInfo> getSubwayListAll(){...}

如何寫好讓別人懂的代碼

接着往下看,這就來到了,最讓人費解的代碼之處了

/** * 獲取所有列車的形式狀態信息,並定時更新 * 邏輯:查詢數據庫中現有的車輛信息,然後根據遍歷車輛信息,取列車編號去查詢大數據端,獲取大數據端的數據, * 進行數據拼接 * 返回內容:返回的數據內容是 車輛的基本信息+大數據端的車輛行駛信息 * @return */
	public void getlist() {
		SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//System.out.println("列車行駛狀態監測啓動"+formatShow.format(new Date()));
		Integer subWayCount = 0;// 列車總量
		subWayStatusCount ssc=new subWayStatusCount();
		ssc.setSubWayOffline(0);// 離線列車的數量
		ssc.setSubWayOnFault(0);// 故障列車的數量
		ssc.setSubWayOnline(0);// 在線列車的數量
		
		try {
			SpecialfieldService specialfieldservice=SpringUtils.getBean(SpecialfieldService.class);
			WebInterfaceService webInterfaceservice=SpringUtils.getBean(WebInterfaceService.class);
			List subwayListAll =getSubwayListAll();
			String dataTime="2017010100000000";
			subWayCount = subwayListAll.size();
			/**將for循環中需要的變量提前定義,再循環體內賦值指定,不再新建,可提升性能**/
			List statusList = new ArrayList();
			Specialfield sf = new Specialfield();
			SubWayInfo m =null;
			BigDataParam bigParam=new BigDataParam();//大數據接口所需的參數
			for (int i = 0; i < subwayListAll.size(); i++) {
				m = (SubWayInfo) subwayListAll.get(i);
					if(!subwayLifeCount.containsKey(m.getId()))
					{
						Map<String,Object> indexMap=new HashMap<String,Object>();
						indexMap.put("lifeSignl", "");//生命信號
						indexMap.put("count",0);//生命信號重複的次數
						subwayLifeCount.put(m.getId(), indexMap);
					}
					SubWayDrivingStatus sds = initSubWayDrivingStatus(m);
					/*獲取大數據端接口參數*/
					bigParam.initBySubwayInfo(m);
					/*獲取特殊字段列表*/
					sf.setCitys(m.getCitys());
					sf.setRoutes(m.getRouteId());
					List<Specialfield> specialfieldList = specialfieldservice.get(sf);
					List<Map<String,Object>> specialfieldGroup=specialfieldservice.
							getSpecialfieldGroupByTrainumInterfacenum(sf);
					List<String> list=new ArrayList<String>();
					for(int j=0;j<specialfieldGroup.size();j++)
					{
						Map<String, Object> mc=specialfieldGroup.get(j);
						bigParam.setData_code(String.valueOf(mc.get("datacoding")).split(","));
						bigParam.setData_type(String.valueOf(mc.get("datatype")).split(","));
						bigParam.setImetro_car_no(String.valueOf(mc.get("trainum")));
						bigParam.setIpackage(mc.get("interfacenum").toString());
						//list.addAll(BigDataWebServiceInterfaceUtil.
						// getRealTimeDataFromFile(webInterfaceservice,bigParam));
						list.addAll(BigDataWebServiceInterfaceUtil.
								getRealTimeData(webInterfaceservice,bigParam));
					}
					if(list.size()<=0)
					{
						sds.setSubwayStatus("離線");;
					}
					else
					{
						if(!specialfieldList.isEmpty())
						{
							Specialfield s=null;
							for (int j=0;j<specialfieldList.size();j++) {
								s=specialfieldList.get(j);
								Field field;
								String itemValue=s.getItemvalue();
								String itemName=s.getItemname();
								String dataCoding=s.getDatacoding();
								try {
									field = sds.getClass().getDeclaredField(itemValue);
									field.setAccessible(true);
									
									for(int r=0;r<list.size();r++)
									{
										String str=list.get(r);
										if (str!=null && !str.isEmpty()) {
											//field.set(sds, "0");
											JSONObject json2 = JSONObject.fromObject(str);
											for (Iterator iter = json2.keys(); iter.hasNext();) {
												String key = (String)iter.next();
												JSONObject json=JSONObject.fromObject(json2.getString(key));
												if(!json.isNullObject()&&!json.isEmpty())
												{
													if(json.containsKey("OP_TIME"))
													{
														dataTime=json.getString("OP_TIME");
													}
													if (json.containsKey(dataCoding)) {
														field.set(sds, json.get(dataCoding).toString());
														if (itemName.equalsIgnoreCase("速度")) {
															sds.setDrivingStatus(MethodUtil.subwayStatusBySpeed(Double.valueOf(json.get(dataCoding).toString())));
														}
														else if (itemName.equalsIgnoreCase("生命信號")) {
															
															String signl=json.get(dataCoding).toString();
															writeLifeMap(signl,m.getId());
														}
														else if (itemName.equalsIgnoreCase("工況")||itemName.equalsIgnoreCase("模式")) {
															String value=json.get(dataCoding).toString();
															List<SpecialFieldText> sptList = s.getShowArr();
															specialCodeShowValue(sptList,value,itemName,sds);
														}
													}
												}
												else
												{
													continue;
												}
													 
											}
									}
									}
								} catch (Exception e) {
									// TODO Auto-generated catch block
									//e.printStackTrace();
									continue;
								}
									
							}
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
						else
						{
							setSubWayStatus(getLifeCount(m.getId()),dataTime,sds,m.getId(), ssc);
						}
					}
					
					statusList.add(sds);
			}
			redis.set("DrivingState", JSONArray.fromObject(statusList).toString());
			redis.set("DrivingState-subWayCount", subWayCount.toString());
			redis.set("DrivingState-subWayOnline", String.valueOf(ssc.getSubWayOnline()));
			redis.set("DrivingState-subWayOffline",String.valueOf(ssc.getSubWayOffline()));
			redis.set("DrivingState-subWayOnFault",String.valueOf(ssc.getSubWayOnFault()));
			if (redis != null) {
				redis.close();
	        }
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

這段代碼總共有148行,初看一下感覺並不複雜,畢竟還有註釋解析方法功能,再一細讀,簡直天堂地獄可遠觀而不可褻玩焉奈何小生沒文化,一句‘臥槽’行天下

也更加驗證了,這孩子是寫C語言的,絕對不適合面向對象編程,一溜到底,由上而下,我是讀了一遍又一遍勉勉強強馬馬虎虎還是不敢說知道它到底要幹什麼?真是防**找這樣的程序員寫代碼在合適不過了!

我先把代碼中明顯的問題找一遍,然後在分析我也不知道對不對的問題

void方法,註釋不應該加@return

因爲這個方法已經是void的,他就沒返回值,所以註釋中不應該出現@return

方法中無關緊要的變量不應該出現

代碼中第一行就有 SimpleDateFormat formatShow = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 這行對代碼沒任何意義,可能測試的是候用到這個時間,因爲下一行註釋了一個打印日期的代碼,既然打印的都註釋了,爲什麼第一行不一起註釋掉呢?

在這裏插入圖片描述
另外,泛型問題,參考前面討論

方法內部註釋

在方法內部,使用註釋因爲其不會生成javadoc所以只需採用 // .../* ... */ 即可

學會使用TODO、FIXME、XXX等特殊註釋

在這裏插入圖片描述
上面這塊代碼中已經處理完了異常時候要繼續工作,就不應該TODO了,直接刪掉不能保留

以上就是這148行代碼,打眼一看就能發現的問題,然後在從上到下,看一遍,還會發現另一個嚴重問題

一個java方法中,不論判斷語句還是循環語句,禁止嵌套3層以上

在看看這個代碼,for循環就已經4層嵌套了,更不用說裏面還有if-else嵌套,這樣一堆代碼堆在一起只能讓人更加迷糊,且不說對不對吧,測試都不好下手,爲你這個方法,需要準備多少測試用例啊?這還是能看到代碼的情況下,要是黑盒測,這段代碼的隱患的多大!!!

直到現在我也不想弄懂上面代碼的處理過程,我要說的是如果遇到這種複雜的處理過程,我們應該怎麼做:

一個方法應儘可能的簡單

我們總是希望一個方法越簡單越好,最好的方法就是隻做一件事情!

使用包裝可以減少業務邏輯的複雜度

比如說上面代碼中4層for嵌套,可以考慮設計三個方法,分別用於包含一套for循環,使其儘量「看起來」不那麼複雜;

通用數據結構,就用類包裝起來;

代碼中需要區分public還是private

在這裏插入圖片描述
上面代碼是用於判斷列車是否有故障,它是服務於getlist()方法,其他任何地方都不會在調用它,那麼這裏方法的類型用public修飾就是不合適的,應該當改成private的作爲類內部的私有方法,代碼中所有的方法都定義成了public的,這是不應該的

包,類,方法,屬性命名原則

  1. 包名的書寫規範 (Package) 推薦使用公司或機構的頂級域名爲包名的前綴,目的是保證各公司/機構內所使用的包名的唯一性。包名全部爲小寫字母,且具有實際的區分意義。
  2. 類名的書寫規範 (Class) 類名必須使用名詞,如果一個類名內含多個單詞,那麼各個單詞第一個字母大寫,後續字母小寫,起伏呈駝峯狀,人稱駝峯式命名。
  3. 駝峯命名法(Camel-Case): 當變量名或函式名是由一個或多個單字連結在一起,而構成的唯一識別字時,首字母以小寫開頭,每個單詞首字母大寫(第一個單詞除外)。

特殊註釋說明

在一些IDE中規定的特殊註釋,例如eclipse中就內置了TODO,FIXME,XXX特殊註釋,同時也可以自定義一些註釋

註釋 說明
TODO 表示需要實現,但目前還未實現的功能
FIXME 代碼是錯誤的,不能工作,需要修復
XXX 勉強可以工作,但是性能差等原因

這些特殊註釋放到代碼中,用於提醒編碼人員注意和查找,如下是eclipse的特殊註釋展示效果
eclipse特殊註釋
另外在Eclipse的Markers標籤下也會查找到所有特殊註釋
在這裏插入圖片描述

javadoc註釋標籤

標籤 說明
@author 標明開發該類模塊的作者,可以多次使用,以指明多個作者
@version 標明該類模塊的版本,也可以使用多次,只有第一次有效
@see 參考轉向,也就是相關主題 @see 類名 @see 完整類名 @see 完整類名#方法名,生成參考其他的JavaDoc文檔的連接
@param 對方法中某參數的說明,使用在方法中,也可以用於類上
@return 對方法返回值的說明,使用在方法中
@exception 對方法可能拋出的異常進行說明 ,使用在方法中
@since 指定最早出現在哪個版本,跟@version有關係
@serial 說明一個序列化屬性
@serialData 說明通過writeObject( ) 和 writeExternal( )方法寫的數據
@serialField 說明一個ObjectStreamField組件
@deprecated 由於某種原因而被宣佈將要被廢棄的方法。
{@docRoot} 指明當前文檔根目錄的路徑
{@inheritDoc} 從直接父類繼承的註釋
{@linkplain #function name} 鏈接,插入一個到另一個主題的鏈接,但是該鏈接顯示純文本字體
{@link #function name} 鏈接,生成參考其他的JavaDoc文檔,它和@see標記的區別在於,@link標記能夠嵌入到註釋語句中,爲註釋語句中的特殊詞彙生成連接。 eg.{@link Hello}
{@value} 顯示常量的值,該常量必須是static屬性
{@code} 相當於添加<code></code>,表名裏面的是代碼
{@literal} 忽略掉標籤解析

結語

不論你是學生還是已經在公司工作了,請認真對待你得代碼。