Java方法中的参数太多,第6部分:方法返回

在当前的系列文章中,我正在致力于减少调用Java方法和构造函数所需的参数数量,到目前为止,我一直专注于直接影响参数本身的方法( 自定义类型参数对象构建器模式方法重载方法命名 )。 鉴于此,对于本系列中的一篇文章,我专门讨论Java方法如何提供返回值,这似乎让我感到惊讶。 但是,方法的返回值会影响开发人员选择通过设置或更改提供的参数(而不是附加或添加更传统的方法返回机制)来提供“返回”值时方法所接受的参数。

非构造方法返回值的“传统方式”都可以在方法签名中指定。 从Java方法返回值的最普遍认可的方法是通过其声明的return type 。 这通常效果很好,但是最常见的一种挫败是允许其仅从 Java方法返回一个值

Java的异常处理机制也是将方法的“结果”保留给调用者的另一种方法。 特别是, 经过检查的异常通过throws子句通告给调用者。 实际上, Jim Waldo在他的《 Java:The Good Parts》一书中指出,当人们将Java异常视为另一种方法返回限制为Throwable类型时,更容易理解Java异常。

尽管方法的返回类型和抛出的异常旨在作为方法将信息返回给调用方的主要方法,但有时还是很想通过传递给方法的参数来返回数据或状态。 当一个方法需要返回多个信息时,Java方法的单值返回似乎是有限的。 尽管异常提供了另一种与调用方进行通信的方式,但似乎几乎所有人都同意,异常应仅用于报告异常情况,而不能用于报告“正常”数据或在控制流中使用。 鉴于只能从一种方法返回一个对象或原语,并且异常仅允许返回Throwable且应仅将其用于报告异常情况,因此Java开发人员劫持参数作为返回数据的替代途径变得越来越有吸引力给来电者。

开发人员可以用来将方法参数用作返回数据的载体的技术是接受可变的参数并改变传入对象的状态。 这些可变对象可以通过方法更改其内容,然后调用者可以访问它提供的对象,以确定被调用方法应用的新状态设置。 尽管可以使用任何可变对象来完成此操作,但对于试图通过参数将值传递回调用方的开发人员而言,集合似乎特别有吸引力。

通过提供的参数将状态传递回被调用有一些缺点。 由于大多数Java开发人员可能期望参数传入而不是传出(并且Java不提供任何代码支持来指定差异),所以这种方法通常违反了令人惊讶原则鲍勃·马丁(Bob Martin)在他的《 清洁代码 》一书中这样写道 :“通常应避免输出参数。” 使用参数作为方法向调用者提供状态或输出的方法的另一个缺点是,这会增加传递给方法的参数的混乱程度。 考虑到这一点,本文的其余部分重点介绍通过传入的参数返回多个值的替代方法。

尽管Java方法只能返回一个对象或基元,但是当人们认为一个对象可以是我们想要的任何对象时,这实际上并不是什么限制。 我见过几种方法,但不推荐使用。 其中之一是返回对象实例的数组或集合,每个Object都是完全不同的,通常是不相关的“事物”。 例如,该方法可能返回三个值作为数组或集合的三个元素。 这种方法的一种变体是使用一对元组n大小的元组返回多个关联值。 此方法的另一个变体是返回Java Map,该Java Map将任意键映射到它们的关联值。 与其他解决方案一样,此方法会给客户端带来不必要的负担,让他们知道那些键是什么,并通过这些键访问映射值。

下一个代码清单包含几种不那么吸引人的方法来返回多个值,而不会劫持方法参数以返回多个值。

通过通用数据结构返回多个值

// ===============================================================
   // NOTE: These examples are intended solely to illustrate a point
   //       and are NOT recommended for production code.
   // ===============================================================

   /**
    * Provide movie information.
    * 
    * @return Movie information in form of an array where details are mapped to
    * elements with the following indexes in the array:
    *       0 : Movie Title
    *       1 : Year Released
    *       2 : Director
    *       3 : Rating
    */
   public Object[] getMovieInformation()
   {
      final Object[] movieDetails =
         {"World War Z", 2013, "Marc Forster", "PG-13"};
      return movieDetails;
   }

   /**
    * Provide movie information.
    * 
    * @return Movie information in form of a List where details are provided
    * in this order: Movie Title, Year Released, Director, Rating.
    */
   public List<Object> getMovieDetails()
   {
      return Arrays.<Object>asList("Ender's Game", 2013, "Gavin Hood", "PG-13");
   }

   /**
    * Provide movie information.
    * 
    * @return Movie information in Map form. Characteristics of the movie can
    * be acquired by looking in the map for these key elements: "Title", "Year",
    * "Director", and "Rating"./
    */
   public Map<String, Object> getMovieDetailsMap()
   {
      final HashMap<String, Object> map = new HashMap();
      map.put("Title", "Despicable Me 2");
      map.put("Year", 2013);
      map.put("Director", "Pierre Coffin and Chris Renaud");
      map.put("Rating", "PG");
      return map;
   }

上面显示的方法确实满足了不通过调用的方法的参数将数据传递回调用方的意图,但是调用方仍然没有必要负担来知道返回数据结构的详细信息。 减少方法的参数数量并且不违反最小惊喜原则是很好的,但是要求客户知道复杂数据结构的复杂性并不是很好。

当我需要返回多个值时,我更喜欢为返回值编写自定义对象。 与使用数组,集合或元组结构相比,这需要做更多的工作,但是很少的额外工作(对于现代Java IDE,通常需要几分钟的时间)会带来可读性和流利性,而这是这些更通用的方法所不具备的。 我的自定义返回对象不必在Javadoc上进行解释或要求我的代码的用户仔细阅读我的代码即可知道在数组或集合中按哪个顺序提供了哪些参数,或者在元组中按哪个值提供了这些参数,而不必在对象上定义方法他们告诉客户他们到底提供了什么。

接下来的代码片段说明了一个主要由NetBeans生成的简单Movie类,该类可以用作返回类型,并且可以返回该类的实例的代码,而不是更通用,更易读的数据结构。

电影.java

package dustin.examples;

import java.util.Objects;

/**
 * Simple Movie class to demonstrate how easy it is to provide multiple values
 * in a single Java method return and provide readability to the client.
 * 
 * @author Dustin
 */
public class Movie
{
   private final String movieTitle;
   private final int yearReleased;
   private final String movieDirectorName;
   private final String movieRating;

   public Movie(String movieTitle, int yearReleased, String movieDirectorName, String movieRating)
   {
      this.movieTitle = movieTitle;
      this.yearReleased = yearReleased;
      this.movieDirectorName = movieDirectorName;
      this.movieRating = movieRating;
   }

   public String getMovieTitle()
   {
      return movieTitle;
   }

   public int getYearReleased()
   {
      return yearReleased;
   }

   public String getMovieDirectorName()
   {
      return movieDirectorName;
   }

   public String getMovieRating()
   {
      return movieRating;
   }

   @Override
   public int hashCode()
   {
      int hash = 3;
      hash = 89 * hash + Objects.hashCode(this.movieTitle);
      hash = 89 * hash + this.yearReleased;
      hash = 89 * hash + Objects.hashCode(this.movieDirectorName);
      hash = 89 * hash + Objects.hashCode(this.movieRating);
      return hash;
   }

   @Override
   public boolean equals(Object obj)
   {
      if (obj == null)
      {
         return false;
      }
      if (getClass() != obj.getClass())
      {
         return false;
      }
      final Movie other = (Movie) obj;
      if (!Objects.equals(this.movieTitle, other.movieTitle))
      {
         return false;
      }
      if (this.yearReleased != other.yearReleased)
      {
         return false;
      }
      if (!Objects.equals(this.movieDirectorName, other.movieDirectorName))
      {
         return false;
      }
      if (!Objects.equals(this.movieRating, other.movieRating))
      {
         return false;
      }
      return true;
   }

   @Override
   public String toString()
   {
      return "Movie{" + "movieTitle=" + movieTitle + ", yearReleased=" + yearReleased + ", movieDirectorName=" + movieDirectorName + ", movieRating=" + movieRating + '}';
   }
}

在单个对象中返回多个详细信息

/**
    * Provide movie information.
    * 
    * @return Movie information.
    */
   public Movie getMovieInfo()
   {
      return new Movie("Oblivion", 2013, "Joseph Kosinski", "PG-13");
   }

Movie课的简单写作花了我大约5分钟的时间。 我使用NetBeans类创建向导来选择类名称和包,然后键入该类的四个属性。 从那里开始,我仅使用NetBeans的“插入代码”机制来插入“获取”访问器方法以及重写的toString()hashCode()equals(Object)方法。 如果我认为不需要这些,可以简化类,但按原样创建确实很容易。 现在,我有一个更有用的返回类型,这由使用该类的代码反映出来。 它几乎不需要在返回类型上使用Javadoc注释,因为该类型可以说明一切,并使用“ get”方法发布其内容。 我觉得,与通过方法参数返回状态或使用更通用且更难使用的返回数据结构之类的替代方法相比,创建这些简单的类以返回多个值的少量额外工作将获得丰厚的回报。

保留要返回给调用方的多个值的自定义类型是一种有吸引力的解决方案,这并不奇怪。 毕竟,从概念上讲,这与我之前写过的关于博客的概念非常相似,后者涉及使用自定义类型和参数对象来传递多个相关参数,而不是将它们全部单独传递。 Java是一种面向对象的语言,当我没有看到在Java代码中使用对象来组织好参数并在一个不错的包中返回值时,它使我感到惊讶。

优势与优势

使用自定义参数对象表示和封装多个返回值的优点是显而易见的。 方法的参数可以保留为“输入”参数,因为所有输出信息(通过异常机制传达的错误信息除外)都可以在方法返回的自定义对象中提供。 与使用通用数组,集合,地图,元组或其他通用数据结构相比,这是一种更清洁的方法,因为所有这些替代方法都将开发工作转移到了所有潜在客户上。

成本与劣势

我看到编写具有多个值的自定义类型用作Java方法的返回类型的缺点很小。 也许最常声称的成本是编写和测试这些类的价格,但是该成本非常小,因为这些类往往很简单,并且因为现代IDE为我们完成了大部分工作。 因为IDE是自动执行的,所以代码通常是正确的。 这些类非常简单,以使代码审阅者易于阅读,并且易于测试。

为了寻找其他成本和劣势,人们可能会争辩说这些类会膨胀代码库和程序包,但我认为这不是一个强有力的论据。 尽管自定义类实现不好的风险很小,但我认为客户机代码更容易混淆更通用的返回类型的解释。 另一个小风险是,开发人员可能将很多无关的东西扔到同一个类中,而这些项目之间的唯一关系是,相同的方法需要返回它们。 即使这样,我能看到的唯一更好的选择是修改代码,而无需返回多个值。 在自定义对象中返回原本不相关的项似乎仍然比在通用数据结构中返回这组不相关的数据更好。 实际上,这些通用数据结构变得更加笨拙并且难以使用,因为它们所拥有的值变得越来越不相关。

结论

自定义类型和参数对象可帮助我们直接解决Java方法中过多参数的问题。 幸运的是,这些自定义类型和返回值对象还可以通过允许我们通过自定义类型和返回值对象返回多个值,而无需添加仅用于将输出信息传递回去的附加参数,从而帮助我们间接减少所需参数的数量。呼叫者,召集者。


翻译自: https://www.javacodegeeks.com/2013/11/too-many-parameters-in-java-methods-part-6-method-returns.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值