Java没有直接的输入输出参数机制,无法简单地实现参数的输入输出功能,因此需要借助其它方法来实现。本文通过实践总结,分享利用方法参数、方法返回值、类字段等方法来实现参数的输入输出,并对比总结各自的优缺点及使用场景。较长,可收藏后再看。

前言

软件开发方法学的泰斗肯特·贝克(Kent Beck)曾说过:

我不是一个伟大的程序员,我只是一个具有良好习惯的优秀程序员。

养成良好的习惯,尤其是不断重构的习惯,是每一个优秀程序员都应该具备的素质。重构(Refactoring)就是在不改变软件现有功能的基础上,通过调整程序的结构、提高程序的质量、优化程序的性能……使其程序的设计模式和架构更趋合理,从而提高软件的稳定性、扩展性和维护性。

一 一个需要重构的方法

需求描述:

要把一个线串(一组经纬度坐标串),按照指定分段长度数组进行按比例划分(由于指定线串的长度较小,可以近似地认为在几何平面上,无需进行球面距离换算)。

代码实现:

1
2  几何辅助类
3
4  c final class GeometryHelper {
5
6   /** 常量相关 */
7   /** 小数位数 */
8  rivate static final int DIGIT_SCALE = 8;
9  /** 放大比例 */
10  private static final double ZOOM_SCALE = 10000000000L;
11  /** 几何工厂 */
12  private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING));13
14  /**
15  * 构造方法
16  */
17  private GeometryHelper() {
18  throw new UnsupportedOperationException();
19     }
20
21 /**
22   * 划分线串
23   *
24  * @param lineString 原始线串
25  * @param segmentLengthes 分段长度数组     26  * @return 线串数组
27  */
28  public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {
29  // 检查分段数量     30   if (Objects.isNull(segmentLengthes) || segmentLengthes.length < 1) {
31 return new LineString[] {lineString};
32  }
33
34   // 计算总共长度
35    double totalLength = Arrays.stream(segmentLengthes)
36 .map(segmentLength -> Math.max(segmentLength, 0.0D))            37    .sum();
38
39       // 计算目标长度
40    double lineLength = lineString.getLength();      41  long[] targetLengthes = Arrays.stream(segmentLengthes)
42   .mapToLong(segmentLength -> getTargetLength(lineLength, totalLength, segmentLength))
43   .toArray();
44
45       // 初始化参数值
46     int index = 1;
47     Coordinate[] coordinates = lineString.getCoordinates();
48     Coordinate coordinate = coordinates[0];
49     int length = targetLengthes.length;
50 LineString[] lineStrings = new
LineString[length];
51
52       // 添加前面N段
53    for (int i = 0; i < length - 1; i++){
54    // 添加线串坐标
55     long addupLength = 0L;
56    List<Coordinate> coordinateList = new ArrayList<>();
57     coordinateList.add(coordinate);
58    for (; index < coordinates.length; index++) {
59     // 计算分段长度
60            long segmentLength = Math.round(coordinate.distance(coordinates[index]) * ZOOM_SCALE);6162                // 根据长度处理                63    boolean isBreak = true;
64    int compareResult = Long.compare(addupLength + segmentLength, targetLengthes[i]);
65         // 根据长度处理: 未达目标长度
66     if (compareResult < 0) {
67     addupLength += segmentLength;
68     coordinate = coordinates[index];                    69     coordinateList.add(coordinate);
70     isBreak = false;
71        }
72           // 根据长度处理: 超过目标长度
73     else if (compareResult > 0) {
74     long deltaLength = targetLengthes[i] - addupLength
75  ;
76             coordinate = buildMiddleCoordinate(coordinate, coordinates[index], segmentLength, deltaLength);
77   }
78         // 根据长度处理: 等于目标长度
79     else {
80            index++;
81     coordinate = coordinates[index];
82   }
83
84         // 是否跳出循环
85           if (isBreak) {
86                   break;
87         }
88      }
89     coordinateList.add(coordinate);
90
91         // 设置线串对象
92    lineStrings[i] = buildLineString(coordinateList);
93     }
94
95       // 添加最后一段
96     lineStrings[length - 1] = buildLineString(coordinates, index, coordinate);
97
98       // 返回线串数组
99     return lineStrings;
100   }
101
102    /**
103   * 构建线串
104    *
105  * @param coordinates 坐标数组
106  * @param index 当前序号
107  * @param coordinate 当前坐标
108  * @return 线串
109  */
110      private static LineString buildLineString(Coordinate[] coordinates, int index, Coordinate coordinate) {
111      List<Coordinate> coordinateList = new ArrayList<>();
112     coordinateList.add(coordinate);
113 coordinateList.addAll(Arrays.asList(ArrayUtils.subarray(coordinates, index, coordinates.length)));
114     return buildLineString(coordinateList);
115    }
116
117   /**
118  * 构建线串
119  *
120   * @param coordinateList 坐标列表
121  * @return 线串
122  */
123   private static LineString buildLineString(List<Coordinate> coordinateList) {
124    return
GEOMETRY_FACTORY.createLineString(coordinateList.toArray(new Coordinate[0]));
125  }
126
127    /**
128    * 构建中间坐标
129    *
130    * @param coordinate1 坐标1
131    * @param coordinate2 坐标2
132    * @param segmentLength 分段长度
133    * @param deltaLength 增量长度
134    * @return 中间坐标
135  */
136    private static Coordinate buildMiddleCoordinate(Coordinate coordinate1, Coordinate coordinate2,        137    long segmentLength, long deltaLength) {
138     double deltaScale = deltaLength * 1.0D / segmentLength;
139   double middleX = round(coordinate1.x + (coordinate2.x - coordinate1.x) * deltaScale, DIGIT_SCALE);
140     double middleY = round(coordinate1.y + (coordinate2.y - coordinate1.y) * deltaScale, DIGIT_SCALE);
141    return new Coordinate(middleX, middleY);
142   }
143
144    /**
145   * 获取目标长度
146   *
147    * @param lineLength 线路长度
148    * @param totalLength 总共长度
149    * @param segmentLength 段长度
150    * @return 目标长度
151    */
152    private static long getTargetLength(double lineLength, double totalLength, double segmentLength) {
153     return Math.round(Math.max(segmentLength, 0.0D) * ZOOM_SCALE * lineLength / totalLength);
154  }
155
156  /**
157     * 四舍五入
158    *
159    * @param value 双精度浮点值
160    * @param scale 保留小数位数
161    * @return 四舍五入值
162    */
163    private static double round(double value, int scale) {
164     return BigDecimal.valueOf(value).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
165 }
166}

备注说明:

在超过目标长度时,获取了一个中间坐标,由于数据精度的关系,这个坐标可能跟上一坐标或下一坐标重合。这里为了降低这块逻辑的复杂度,没有进行前后坐标的去重处理。

存在问题:

在方法splitLineString(划分线串)中,存在一个两层循环,导致了方法逻辑复杂、层级较深、代码量大。如果把外层循环体提炼为一个方法,就能够使代码更简洁、更清晰、更容易维护。

二 一次失败的重构经历

理论依据:

当看到一个方法定义过长或者这段方法需要很多注释才能让人理解的时候,这时候就要考虑是不是把这个方法的部分代码提取出来,形成一个新的方法,方便调用和理解,同时也减小方法的粒度。我们把这种方法叫做提炼函数(Extract Function),在Java语言中可叫做提炼方法(Extract Method)。

重构步骤:⬇️

  • 创建一个新方法,并根据这个方法的意图来命名;
  • 将待提炼的代码段从原方法中拷贝到新方法中;
  • 检查提炼的代码段,把缺少的变量添加到方法的参数中;
  • 如果部分参数成对出现,可以把这些参数合并为一个参数;
  • 如果方法需要有返回值,确定返回值的类型,并在合适的位置返回;
  • 在原方法中,删除被提炼的代码段,替换为新方法的调用。

代码实现:

1    /**
2    * 几何辅助类
3    */
4  public final class GeometryHelper {
5
6    /** 原有静态常量 */
7    ......
8
9    /**
10   * 划分线串
11   *
12   * @param lineString 原始线串
13   * @param segmentLengthes 分段长度数组
14   * @return 线串数组
15    */
16    public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {
17    // 原有计算逻辑
18     ......
19
20       // 初始化参数值
21       int index = 1;
22     Coordinate[] coordinates = lineString.getCoordinates();
23     Coordinate coordinate = coordinates[0];
24   int length = targetLengthes.length;        LineString[]
25   lineStrings = new LineString[length];
26
27       // 添加前面N段
28    for (int i = 0; i < length - 1; i++) {
29         lineStrings[i] = combineLineString(coordinates, index, coordinate, targetLengthes[i]);
30       }
31
32        // 添加最后一段
33   lineStrings[length - 1]
buildLineString(coordinates, index, coordinate);
34
35        // 返回线串数组
36      return lineStrings;
37   }
38
39   /**
40  * 组装线串
41   *
42    * @param coordinates 坐标数组
43    * @param index 当前序号
44    * @param coordinate 当前坐标
45    * @param targetLength 目标长度
46    * @return 线串
47    */
48    private static LineString combineLineString(Coordinate[] coordinates, int index, Coordinate coordinate, long targetLength) {
49      // 添加线串坐标
50      long addupLength = 0L;
51     List<Coordinate> coordinateList = new ArrayList<>();
52    coordinateList.add(coordinate);
53    for (; index < coordinates.length; index++) {
54          // 计算分段长度
55           long segmentLength = Math.round(coordinate.distance(coordinates[index]) * ZOOM_SCALE);
56
57            // 根据长度处理
58     boolean isBreak = true;
59     int compareResult = Long.compare(addupLength + segmentLength, targetLength);
60         // 根据长度处理: 未达目标长度
61     if (compareResult < 0) {                62     addupLength += segmentLength;                63  coordinate = coordinates[index];                64  coordinateList.add(coordinate);                65  isBreak = false;
66           }
67         // 根据长度处理: 超过目标长度
68  else if (compareResult > 0) {
69   long deltaLength = targetLength - addupLength;
70              coordinate = buildMiddleCoordinate(coordinate, coordinates[index], segmentLength, deltaLength);
71            }
72          // 根据长度处理: 等于目标长度
73  else {
74            index++;
75   coordinate = coordinates[index];
76   }
77
78        // 是否跳出循环
79           if (isBreak) {
80   break;
81          }
82       }
83  coordinateList.add(coordinate);
84
85        // 返回线串对象
86       return buildLineString(coordinateList);
87    }
88
89    /** 原有静态方法 */
90  ......
91
92

先写到这,有一部分没有写完,觉得有用双击收藏,仅此一家。

地址栏 输入 参数 刷新参数丢失_Java 编程技巧:如何实现参数的输入输出?相关推荐

  1. java注解约束参数为固定值_Java学习 使用注解将参数的值限定

    前言 在Java的开发中,我们经常需要输入一些int或者String类型的值,而这些值可能仅仅用于代表状态或者类别.但是我们只希望这个参数的值输入0 到 5 这个范围的值,如果多输入大了我们的代码上并 ...

  2. sql2008安装时提示参数不能为空_Java Validation API,实现参数的合法性校验

    Hibernate Validator是Java Validation API(JSR 303)标准的一个具体实现,用于对参数进行合法性校验.校验数据在任何应用中都是一个很常见的任务,所以JCP组织定 ...

  3. java编程技巧_Java编程技巧

    1.在A类中申请资源后一定要释放掉,或者提供释放的方法或接口.最好在同一个方法中释放.绝对不可将申请的资源提供给其他类,让别人来释放. 2.在操作socket等时,一定要使用finally关闭资源,否 ...

  4. 替代java参数_java – 使用Void作为可选参数的更好的替代方法

    我有一个接口指定方法,它采用泛型类型作为输入,用于创建URL. interface UrlGenerator { String prepareUrl( T input ); } 有一个实现不需要参数. ...

  5. 坐标转换 四参数/七参数/正形变换 ∈ C# 编程笔记

    更新日期:2020/4/7 文章目录 2.平面坐标转换 四参数/正形变换 2.1 直接法 2.2 平差法 2.3 正形变换法 附 简化版正形变换法 代码 2.4 七参数坐标转换 [注1]其中的代码也许 ...

  6. Matlab编程技巧:通过脚本获取/修改Simulink信号线参数

    上一篇博客<Matlab编程技巧:批量获取/修改Simulink模块参数>中,说明了如果通过matlab脚本批量获取/修改Simulink模块参数.具体方法可以参考https://blog ...

  7. Linux shell编程学习实例与参数分析(一)

    第一章:shell基础 ●umask   --查看当前用户创建文件或文件夹时的默认权限 eg: [test@szbirdora 1]$umask 0002 [test@szbirdora 1]$ls ...

  8. Java编程技巧:如何实现参数的输入输出?

    简介:Java没有直接的输入输出参数机制,无法简单地实现参数的输入输出功能,因此需要借助其它方法来实现.本文作者通过实践总结,分享利用方法参数.方法返回值.类字段等方法来实现参数的输入输出,并对比总结 ...

  9. 编程题:带参数的宏定义来实现,求圆的周长和面积。

    编程题:带参数的宏定义来实现,求圆的周长和面积. #include<stdio.h> #define PI 3.14159 #define L(r) 2*PI*(r) #define S( ...

最新文章

  1. 34岁,外企倒闭成功上岸大厂,50K,附面试秘籍
  2. SAP UI5和Angularjs事件处理机制的实现比较
  3. 自定义SharePoint 2013 元数据选择控件
  4. beginnersbook C 语言示例·翻译完成 | ApacheCN
  5. 无人机rtmp推流直播解决方案
  6. 你们是不是很缺大数据工程师?
  7. 一种数字全息自动聚焦技术研究及实例分析
  8. Win11局域网内安装IIS
  9. 基于fpga的256M SDRAM控制器 【内含256m sdram仿真模型】
  10. PHPStrom 快捷键
  11. 大智慧策略投资终端_智慧历史:不需要宏伟的策略,只需开放
  12. html自动生成拼音五笔,如何根据单元格汉字自动生成拼音码和五笔码
  13. PS自用(抠图、调色)
  14. windows免安装版mysql
  15. 春节期间,怎样晒朋友圈才安全?
  16. Java当中的IO流(中)
  17. D35 876. Middle of the Linked List
  18. 你想知道的直播技术都在这里了
  19. C#——TreeView控件使用方法
  20. DMA漏损管理系统(Axure高保真原型)

热门文章

  1. python400集视频教程-微软官方出品的400集Python精品视频教程,这正是我们急需的!...
  2. python自动化办公要学多久-深圳用python进行办公自动化都需要学习什么知识呢,谁来说下...
  3. python官网下载安装-Python2.7.6下载
  4. python是什么意思-python是什么意思
  5. python语言-python语言基本语句用法总结
  6. python入门基础知识实例-Python入门,原来如此简单!
  7. 一种基于语音识别的机器人语义识别系统的制作方法
  8. 百度语音识别最新资讯
  9. R-查询子段元素和 提前储存
  10. 前端elementui el-popover 多行文本换行显示优化