阿里妹导读:Java没有直接的输入输出参数机制,无法简单地实现参数的输入输出功能,因此需要借助其它方法来实现。本文作者通过实践总结,分享利用方法参数、方法返回值、类字段等方法来实现参数的输入输出,并对比总结各自的优缺点及使用场景。较长,可收藏后再看。
文末福利:开发者训练营来了!
我不是一个伟大的程序员,我只是一个具有良好习惯的优秀程序员。
/*** 几何辅助类*/public final class GeometryHelper {/** 常量相关 *//** 小数位数 */private static final int DIGIT_SCALE = 8;/** 放大比例 */private static final double ZOOM_SCALE = 10000000000L;/** 几何工厂 */private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING));/*** 构造方法*/private GeometryHelper() {throw new UnsupportedOperationException();}/*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 检查分段数量if (Objects.isNull(segmentLengthes) || segmentLengthes.length < 1) {return new LineString[] {lineString};}// 计算总共长度double totalLength = Arrays.stream(segmentLengthes).map(segmentLength -> Math.max(segmentLength, 0.0D)).sum();// 计算目标长度double lineLength = lineString.getLength();long[] targetLengthes = Arrays.stream(segmentLengthes).mapToLong(segmentLength -> getTargetLength(lineLength, totalLength, segmentLength)).toArray();// 初始化参数值int index = 1;Coordinate[] coordinates = lineString.getCoordinates();Coordinate coordinate = coordinates[0];int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {// 添加线串坐标long addupLength = 0L;List<Coordinate> coordinateList = new ArrayList<>();coordinateList.add(coordinate);for (; index < coordinates.length; index++) {// 计算分段长度long segmentLength = Math.round(coordinate.distance(coordinates[index]) * ZOOM_SCALE);// 根据长度处理boolean isBreak = true;int compareResult = Long.compare(addupLength + segmentLength, targetLengthes[i]);// 根据长度处理: 未达目标长度if (compareResult < 0) {addupLength += segmentLength;coordinate = coordinates[index];coordinateList.add(coordinate);isBreak = false;}// 根据长度处理: 超过目标长度else if (compareResult > 0) {long deltaLength = targetLengthes[i] - addupLength;coordinate = buildMiddleCoordinate(coordinate, coordinates[index], segmentLength, deltaLength);}// 根据长度处理: 等于目标长度else {index++;coordinate = coordinates[index];}// 是否跳出循环if (isBreak) {break;}}coordinateList.add(coordinate);// 设置线串对象lineStrings[i] = buildLineString(coordinateList);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, index, coordinate);// 返回线串数组return lineStrings;}/*** 构建线串** @param coordinates 坐标数组* @param index 当前序号* @param coordinate 当前坐标* @return 线串*/private static LineString buildLineString(Coordinate[] coordinates, int index, Coordinate coordinate) {List<Coordinate> coordinateList = new ArrayList<>();coordinateList.add(coordinate);coordinateList.addAll(Arrays.asList(ArrayUtils.subarray(coordinates, index, coordinates.length)));return buildLineString(coordinateList);}/*** 构建线串** @param coordinateList 坐标列表* @return 线串*/private static LineString buildLineString(List<Coordinate> coordinateList) {return GEOMETRY_FACTORY.createLineString(coordinateList.toArray(new Coordinate[0]));}/*** 构建中间坐标** @param coordinate1 坐标1* @param coordinate2 坐标2* @param segmentLength 分段长度* @param deltaLength 增量长度* @return 中间坐标*/private static Coordinate buildMiddleCoordinate(Coordinate coordinate1, Coordinate coordinate2,long segmentLength, long deltaLength) {double deltaScale = deltaLength * 1.0D / segmentLength;double middleX = round(coordinate1.x + (coordinate2.x - coordinate1.x) * deltaScale, DIGIT_SCALE);double middleY = round(coordinate1.y + (coordinate2.y - coordinate1.y) * deltaScale, DIGIT_SCALE);return new Coordinate(middleX, middleY);}/*** 获取目标长度** @param lineLength 线路长度* @param totalLength 总共长度* @param segmentLength 段长度* @return 目标长度*/private static long getTargetLength(double lineLength, double totalLength, double segmentLength) {return Math.round(Math.max(segmentLength, 0.0D) * ZOOM_SCALE * lineLength / totalLength);}/*** 四舍五入** @param value 双精度浮点值* @param scale 保留小数位数* @return 四舍五入值*/private static double round(double value, int scale) {return BigDecimal.valueOf(value).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();}}
创建一个新方法,并根据这个方法的意图来命名;
将待提炼的代码段从原方法中拷贝到新方法中;
检查提炼的代码段,把缺少的变量添加到方法的参数中;
如果部分参数成对出现,可以把这些参数合并为一个参数;
如果方法需要有返回值,确定返回值的类型,并在合适的位置返回;
在原方法中,删除被提炼的代码段,替换为新方法的调用。
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值int index = 1;Coordinate[] coordinates = lineString.getCoordinates();Coordinate coordinate = coordinates[0];int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, index, coordinate, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, index, coordinate);// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param index 当前序号* @param coordinate 当前坐标* @param targetLength 目标长度* @return 线串*/private static LineString combineLineString(Coordinate[] coordinates, int index, Coordinate coordinate, long targetLength) {// 添加线串坐标long addupLength = 0L;List<Coordinate> coordinateList = new ArrayList<>();coordinateList.add(coordinate);for (; index < coordinates.length; index++) {// 计算分段长度long segmentLength = Math.round(coordinate.distance(coordinates[index]) * ZOOM_SCALE);// 根据长度处理boolean isBreak = true;int compareResult = Long.compare(addupLength + segmentLength, targetLength);// 根据长度处理: 未达目标长度if (compareResult < 0) {addupLength += segmentLength;coordinate = coordinates[index];coordinateList.add(coordinate);isBreak = false;}// 根据长度处理: 超过目标长度else if (compareResult > 0) {long deltaLength = targetLength - addupLength;coordinate = buildMiddleCoordinate(coordinate, coordinates[index], segmentLength, deltaLength);}// 根据长度处理: 等于目标长度else {index++;coordinate = coordinates[index];}// 是否跳出循环if (isBreak) {break;}}coordinateList.add(coordinate);// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */......}
When you’re passing primitives into a method,you get a distinct copy of the primitive. When you’re passing a reference into a method, you get a copy of the reference.
当您将基本类型传递到方法中时,您将得到该基本类型的副本。当您将对象引用传递到方法中时,您将得到该对象引用的副本。
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值Coordinate[] coordinates = lineString.getCoordinates();InoutParameter inoutParameter = new InoutParameter(1, coordinates[0]);int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, inoutParameter, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, inoutParameter.getIndex(), inoutParameter.getCoordinate());// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param inoutParameter 输入输出参数* @param targetLength 目标长度* @return 线串*/private static LineString combineLineString(Coordinate[] coordinates, InoutParameter inoutParameter, long targetLength) {// 获取输入参数int index = inoutParameter.getIndex();Coordinate coordinate = inoutParameter.getCoordinate();// 添加线串坐标......// 设置输出参数inoutParameter.setIndex(index);inoutParameter.setCoordinate(coordinate);// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */....../*** 输入输出参数类*/private static class InoutParameter {/** 当前序号 */private int index;/** 当前坐标 */private Coordinate coordinate;}}
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值int[] indexHolder = new int[] {1};Coordinate[] coordinates = lineString.getCoordinates();Coordinate[] coordinateHolder = new Coordinate[] {coordinates[0]};int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, indexHolder, coordinateHolder, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, indexHolder[0], coordinateHolder[0]);// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param indexHolder 序号支撑* @param coordinateHolder 坐标支撑* @param targetLength 目标长度* @return 线串*/private static LineString combineLineString(Coordinate[] coordinates, int[] indexHolder, Coordinate[] coordinateHolder, long targetLength) {// 获取支撑取值int index = indexHolder[0];Coordinate coordinate = coordinateHolder[0];// 添加线串坐标......// 设置支撑取值indexHolder[0] = index;coordinateHolder[0] = coordinate;// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */......}
Apache的commons-lang3提供的元组类:
Pair<L, R>:MutablePair<L, R>,ImmutablePair<L, R>
Triple<L, M, R>:MutableTriple<L, M, R>、ImmutableTriple<L, M, R>
JavaTuples提供的元组类:
Unit<A>
Pair<A,B>,KeyValue<A,B>
Triplet<A,B,C>
Quartet<A,B,C,D>
Quintet<A,B,C,D,E>
Sextet<A,B,C,D,E,F>
Septet<A,B,C,D,E,F,G>
Octet<A,B,C,D,E,F,G,H>
Ennead<A,B,C,D,E,F,G,H,I>
Decade<A,B,C,D,E,F,G,H,I,J>
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值Coordinate[] coordinates = lineString.getCoordinates();MutablePair<Integer, Coordinate> mutablePair = MutablePair.of(1, coordinates[0]);int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, mutablePair, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, mutablePair.getLeft(), mutablePair.getRight());// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param mutablePair 当前配对* @param targetLength 目标长度* @return 线串*/private static LineString combineLineString(Coordinate[] coordinates, MutablePair<Integer, Coordinate> mutablePair,long targetLength) {// 获取配对取值int index = mutablePair.getLeft();Coordinate coordinate = mutablePair.getRight();// 添加线串坐标......// 设置配对取值mutablePair.setLeft(index);mutablePair.setRight(coordinate);// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */......}
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值Coordinate[] coordinates = lineString.getCoordinates();ObjectHolder<Integer> indexHolder = new ObjectHolder<>(1);ObjectHolder<Coordinate> coordinateHolder = new ObjectHolder<>(coordinates[0]);int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, indexHolder, coordinateHolder, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, indexHolder.getValue(), coordinateHolder.getValue());// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param indexHolder 序号支撑* @param coordinateHolder 坐标支撑* @param targetLength 目标长度* @return 线串*/private static LineString combineLineString(Coordinate[] coordinates, ObjectHolder<Integer> indexHolder, ObjectHolder<Coordinate> coordinateHolder, long targetLength) {// 获取支撑取值int index = indexHolder.getValue();Coordinate coordinate = coordinateHolder.getValue();// 添加线串坐标......// 设置支撑取值indexHolder.setValue(index);coordinateHolder.setValue(coordinate);// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */......}/*** 对象支撑类*/public class ObjectHolder<T> {/** 对象取值 */private T value;}
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值int index = 1;Coordinate[] coordinates = lineString.getCoordinates();Coordinate coordinate = coordinates[0];int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {ReturnResult result = combineLineString(coordinates, index, coordinate, targetLengthes[i]);index = result.getIndex();coordinate = result.getCoordinate();lineStrings[i] = result.getLineString();}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, index, coordinate);// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param index 当前序号* @param coordinate 当前坐标* @param targetLength 目标长度* @return 返回值*/private static ReturnResult combineLineString(Coordinate[] coordinates, int index, Coordinate coordinate, long targetLength) {// 添加线串坐标......// 返回输出结果return new ReturnResult(index, coordinate, buildLineString(coordinateList));}/** 原有静态方法 */....../*** 返回值类*/private static class ReturnResult {/** 当前序号 */private int index;/** 当前坐标 */private Coordinate coordinate;/** 线串对象 */private LineString lineString;}}
/*** 几何辅助类*/public final class GeometryHelper {/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值int index = 1;Coordinate[] coordinates = lineString.getCoordinates();Coordinate coordinate = coordinates[0];int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {Triple<Integer, Coordinate, LineString> triple = combineLineString(coordinates, index, coordinate, targetLengthes[i]);index = triple.getLeft();coordinate = triple.getMiddle();lineStrings[i] = triple.getRight();}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, index, coordinate);// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param index 当前序号* @param coordinate 当前坐标* @param targetLength 目标长度* @return 返回值*/private static Triple<Integer, Coordinate, LineString> combineLineString(Coordinate[] coordinates, int index, Coordinate coordinate, long targetLength) {// 添加线串坐标......// 返回输出结果return ImmutableTriple.of(index, coordinate, buildLineString(coordinateList));}/** 原有静态方法 */......}
/*** 几何辅助类*/public final class GeometryHelper {/** 属性相关 *//** 当前序号支撑 */private static final ThreadLocal<Integer> INDEX_HOLDER = new ThreadLocal<>();/** 当前坐标支撑 */private static final ThreadLocal<Coordinate> COORDINATE_HOLDER = new ThreadLocal<>();/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值INDEX_HOLDER.set(1);Coordinate[] coordinates = lineString.getCoordinates();COORDINATE_HOLDER.set(coordinates[0]);int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, INDEX_HOLDER.get(), COORDINATE_HOLDER.get());// 清除支撑类INDEX_HOLDER.remove();COORDINATE_HOLDER.remove();// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param targetLength 目标长度* @return 线串*/private static LineString combineLineString(Coordinate[] coordinates, long targetLength) {// 获取支撑取值int index = INDEX_HOLDER.get();Coordinate coordinate = COORDINATE_HOLDER.get();// 添加线串坐标......// 设置支持取值INDEX_HOLDER.set(index);COORDINATE_HOLDER.set(coordinate);// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */......}
/*** 几何辅助类*/public final class GeometryHelper {// 原有构造方法....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public static LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {SplitLineStringAlgorithm algorithm = new SplitLineStringAlgorithm();return algorithm.splitLineString(lineString, segmentLengthes);}}/*** 划分线串算法类*/public class SplitLineStringAlgorithm {/** 属性相关 *//** 当前序号 */private int index;/** 当前坐标 */private Coordinate coordinate;/** 原有静态常量 */....../*** 划分线串** @param lineString 原始线串* @param segmentLengthes 分段长度数组* @return 线串数组*/public LineString[] splitLineString(LineString lineString, double[] segmentLengthes) {// 原有计算逻辑......// 初始化参数值index = 1;Coordinate[] coordinates = lineString.getCoordinates();coordinate = coordinates[0];int length = targetLengthes.length;LineString[] lineStrings = new LineString[length];// 添加前面N段for (int i = 0; i < length - 1; i++) {lineStrings[i] = combineLineString(coordinates, targetLengthes[i]);}// 添加最后一段lineStrings[length - 1] = buildLineString(coordinates, index, coordinate);// 返回线串数组return lineStrings;}/*** 组装线串** @param coordinates 坐标数组* @param targetLength 目标长度* @return 线串*/private LineString combineLineString(Coordinate[] coordinates, long targetLength) {// 添加线串坐标......// 返回线串对象return buildLineString(coordinateList);}/** 原有静态方法 */......}
各种实现方法有利有弊,应当根据具体的使用场景,来选择最适合的实现方法。
根据参数和返回值的类型选择实现方法:输入输出参数尽量使用方法参数实现,返回值尽量使用返回值实现。
根据参数和返回值的数量选择实现方法:数量少的尽量使用支撑类和元组类,数量多的尽量使用自定义类。
不建议使用一些取巧的实现方法,比如:3.2.利用单值数组实现、5.1.利用线程本地变量实现。
不推荐使用对象数组和对象Map,Java是强类型定义语言,不建议使用强制数据类型转化。
最适合本文中案例的实现方法是——3.4.利用支撑类实现。
吾生也有涯,而知也无涯。以有涯随无涯,殆已!
云栖训练营提前开启报名,本次共3大领域8个训练营,包含K8S训练营、小程序与开发,DevOps日志分析实战、mPaaS小程序训练营,云开发Web实战训练营等。阿里云专家授课,3-7天带你轻松get实战能力,还有丰厚奖品,期待你“满载而归”!