Java:For 循环和 If 算法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3779514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 04:54:05  来源:igfitidea点击:

Java: For loop and If algorithm

javaalgorithmloopsif-statement

提问by Ben C.

I've this question from an assignment to create a Store which rent out books, using a Store.java and Book.java. I've finished this assignment, but I'm curious for better algorithm to a specific part.

我从一个任务中得到了这个问题,即使用 Store.java 和 Book.java 创建一个出租书籍的商店。我已经完成了这个作业,但我很好奇特定部分的更好算法。

--

——

Book.java

书.java

public class Book {

    private String name;

    Book(String name)
        this.name = name;

    public String getName()
        return name;

}

Store.java

商店.java

Inside main();

内部 main();

 Book bookObj[] = new Book[3]; //Create 3 Array of Object.
 bookObj[0] = new Book("Game Over");
 bookObj[1] = new Book("Shrek"); 
 bookObj[2] = new Book("Ghost");
 Scanner console = new Scanner(System.in)
 input = console.nextLine();

Assuming, input = Devil.

假设,输入 = 魔鬼。

Now, I need to do a simple search to check whether the specific book exist.

现在,我需要做一个简单的搜索来检查特定的书是否存在。

Example:

例子:

 for(int i = 0; i < bookObj.length; i++) {
     if(bookObj[i].getName().equals(input))
         System.out.println("Book Found!");
 }

Apparently, this is a for loop that cycles through the array of object and checks whether such Book exist. Now, the problem arise when I want to give an output that the Book was not found.

显然,这是一个循环遍历对象数组并检查此类 Book 是否存在的 for 循环。现在,当我想给出未找到 Book 的输出时,问题就出现了。

Example:

例子:

 for(int i = 0; i < bookObj.length; i++) {
     if(bookObj[i].getName().equals(input))
         System.out.println("Book Found!");
     else
         System.out.println("Book not Found!");
 }

The problem with the above code is that Book not Found would be printed thrice. My goal is to avoid such problem. I do have solutions to this, but I'm still in search for a better one to use that utilizes getName(), which in my opinion still has room to improve.

上面代码的问题是 Book not Found 会打印三次。我的目标是避免这样的问题。我确实对此有解决方案,但我仍在寻找使用 getName() 的更好的解决方案,在我看来,它仍有改进的空间。

Usually, in structural programming, I would do the following,

通常,在结构化编程中,我会执行以下操作,

for(int i = 0; i < bookObj.length; i++) {
     if(bookObj[i].getName().equals(input))
         System.out.println("Book Found!");
     else if(i == bookObj.length - 1)
         System.out.println("Book not Found!");
 }

This is useful to tell whether it's the end of the loop, and the search has ended, but there was no successful result from the search.

这有助于判断循环是否结束,搜索已经结束,但搜索没有成功结果。

How should I think of it in Object Oriented way?

我应该如何以面向对象的方式思考它?

All in all, my question is,

总而言之,我的问题是,

  1. Is there a better way to write the above code rather than checking that it's the end of the line?
  2. Is there a better way to utilize getName() method or to use other methods?
  1. 有没有更好的方法来编写上面的代码而不是检查它是否是行尾?
  2. 有没有更好的方法来利用 getName() 方法或使用其他方法?

采纳答案by Péter T?r?k

You should loop through the array and use an index / boolean flag to store whether or not the book is found. Then print the message in the end, based on the index / flag value.

您应该遍历数组并使用索引/布尔标志来存储是否找到了这本书。然后根据索引/标志值在最后打印消息。

int foundAtIndex = -1;
for(int i = 0; i < bookObj.length; i++) {
    if(bookObj[i].getName().equals(input)) {
        foundAtIndex = i;  // store the actual index for later use
        break;             // no need to search further
    }
}
if(foundAtIndex >= 0)
    System.out.println("Book Found!");
else
    System.out.println("Book not Found!");

Alternatively (unless your assignment specifically requires using an array) you should prefer a Set, which can do the search for you with a single call to contains().

或者(除非你的任务特别需要使用数组)你应该更喜欢 a Set,它可以通过一次调用来搜索你contains()

How should I think of it in Object Oriented way?

我应该如何以面向对象的方式思考它?

When looking at a single method, there is not much difference between procedural and OO style. The differences start to appear at a higher level, when trying to organize a bunch of conceptually related data and methods that operate on these.

在查看单个方法时,过程式和 OO 风格之间没有太大区别。当试图组织一堆概念相关的数据和对这些数据进行操作的方法时,差异开始出现在更高的层次上。

The OO paradigm is to tie the methods to the data they operate on, and encapsulate both into coherent objects and classes. These classes are preferably representations of important domain concepts. So for your book store, you may want to put all book related code into your Bookclass. However, the above search method (and the collection of books it operates on) is not related to any particular book instance, so you have different choices:

OO 范式是将方法与它们操作的数据联系起来,并将两者封装成一致的对象和类。这些类最好是重要领域概念的表示。因此,对于您的书店,您可能希望将所有与图书相关的代码放入您的Book类中。但是,上述搜索方法(及其操作的图书集合)与任何特定图书实例无关,因此您有不同的选择:

  • put both the collection of books and the search method into Store(probably as regular members), or
  • put them into Bookas staticmembers.
  • 把藏书和搜索方法都放进去Store(可能是普通会员),或者
  • 把他们Book作为static成员。

The first choice is more natural, so I normally would prefer that. However, under specific circumstances the second option might be preferable. In (OO) design, there are hardly ever clean "yes/no" answers - rather tradeoffs between different options, each having their own strengths and weaknesses.

第一个选择更自然,所以我通常更喜欢那个。但是,在特定情况下,第二种选择可能更可取。在(OO)设计中,几乎没有明确的“是/否”答案——而是不同选项之间的权衡,每个选项都有自己的优点和缺点。

回答by Thomas L?tzer

You could introduce state and remember whether you have found the book or not.

你可以介绍 state 并记住你是否找到了这本书。

If you're not using Java 1.4 or earlier, you could also use the foreach loop syntax:

如果您不使用 Java 1.4 或更早版本,您还可以使用 foreach 循环语法:

boolean bookFound = false;
for(Book currentBook : bookObj) {
     if(currentBook.getName().equals(input))
     //TODO: see above
}

Also, I would suggest looking into the Collections library, and replace your array with a list or set:

另外,我建议查看Collections library,并用列表或集合替换您的数组:

Set<Book> books = new HashSet<Book>();
books.put(new Book("Game Over"));
books.put(new Book("Shrek")); 
books.put(new Book("Ghost"));

And, while were at it, you could also think about when two books are equal and override equals() and hashCode() accordingly. If equal() would be changed to check the title, you could simply use books.contains(new Book(input));and have the libraries do the work for you.

而且,在此期间,您还可以考虑何时两本书相等并相应地覆盖 equals() 和 hashCode()。如果将 equal() 更改为检查标题,您可以简单地使用books.contains(new Book(input));并让库为您完成工作。

回答by Designpattern

To solve the problem in a better way you must understand that the power of Java comes not from the language itself but from the Java Framework.

要以更好的方式解决问题,您必须了解 Java 的力量不是来自语言本身,而是来自 Java 框架。

You should learn the usage of the Java Collectionclasses (never work with arrays anymore). Then you will be able to solve the search with just one line of code:

您应该学习Java Collection类的用法(不再使用数组)。然后你就可以只用一行代码来解决搜索:

ArrayList<Book> listOfBooks;
// init your list here
listOfBooks.contains(new Book(input));

To make this work, you must also learn how to correctly implement the equals() method of your Book class.

为了使这项工作,您还必须学习如何正确实现 Book 类的 equals() 方法。

Happy learning!

快乐学习!

回答by Jér?me Radix

Here is a working solution :

这是一个有效的解决方案:

import java.util.Scanner;

public class Store {

   private static class Book {

      private String name;

      Book(String name) {
         this.name = name;
      }

      public String getName() {
         return name;
      }

   }

   public static void main(String[] args) {

      String input;

      Book[] bookObj = new Book[3];

      bookObj[0] = new Book("Game Over");
      bookObj[1] = new Book("Shrek"); 
      bookObj[2] = new Book("Ghost");

      Scanner console = new Scanner(System.in);
      input = console.nextLine();

      boolean found = false;
      int i = 0;
      while(!found && i < bookObj.length) {

         if(bookObj[i].getName().equals(input)) {

            System.out.println("Book Found at position : " + i);
            found = true;

         } else {
            i++;
         }
      }

      if(!found) {
         System.out.println("Book not Found!");
      }

      // Here i contains the indice of the element found in the array.

   }

}

回答by chubbsondubs

You've gotten some pretty good advice thus far. You asked if there was a more Object Oriented way of thinking about the problem so I thought I'd try and shed some light on it. As Peter already mentioned at this level of the design it's a single method implementation so the approach is going to be fairly similar as say a procedural approach. What's the advantage? In a word reuse. If you needed to find a book by name in lots of places then moving the code to it's own class will help.

到目前为止,你已经得到了一些很好的建议。你问是否有一种更面向对象的方式来思考这个问题,所以我想我会尝试阐明它。正如彼得在设计的这个级别已经提到的那样,它是一个单一的方法实现,因此该方法将与程序方法非常相似。有什么好处?一句话重用。如果您需要在很多地方按名称查找一本书,那么将代码移动到它自己的类会有所帮助。

So what you have is a single Book instance to encapsulate behavior around a single book, but you want to have behavior about multiple books, or a collection of books. You can keep the data (array of books), and the method that account on them separate as you outlined in your program. However, if we wanted to collect a place for doing behavior on a collection of books we can define a new class. Let's call it Library, and we might do something like the following:

因此,您拥有的是单个 Book 实例来封装围绕一本书的行为,但您希望拥有关于多本书或一组书籍的行为。您可以按照您在程序中的概述,将数据(书籍数组)和对它们进行会计处理的方法分开。但是,如果我们想收集一个地方来对一组书籍进行行为,我们可以定义一个新类。我们称之为库,我们可能会做如下的事情:

public class Library {
   private Book[] books;
   private bookCount = 0;

   public Library( int numberOfTotalBooks ) {
      books = new Book[numberOfTotalBooks];
   }

   public boolean addBook( Book book ) {
      if( bookCount < book.length ) {
         books[bookCount++] = book;
         return true;
      }
      return false;
   }

   public Book findByTitle( String title ) {
       for( int i = 0; i < bookCount; i++ ) {
          if( books[i].getTitle().equals( title ) ) {
             return books[i];
          }
       }
       // didn't find one
       return null;
   }
}

So a couple of things to note about doing things this way. One is that when we work with a Library we don't know there is an Array back there. We could use an array, a Set, a List, or a database (most common). The point being the code that calls these functions just works with the interface of Library (not a literal Java interface, but the method signature of Library). Also this is a higher level interface. We don't worry about iterating over the books, doing for loops, if statements, etc. We just call a method saying "Hey find this book title in the Library". How that's done we don't care. This is the basic tenant of Object Orientation called encapsulation, and it's deceptively powerful. It's really about how we delegate responsibility in our program, and give the details of a job to individual class or classes. If Library had only public members (i.e. books and bookCount), or getter/setters then the client wouldn't be getting any advantages because the client would still have to do all the heavy lifting. The trick to OO is figuring out what can be delegated out of an object, without creating problems. This takes practice, and experience.

因此,关于以这种方式做事,有几点需要注意。一是当我们使用图书馆时,我们不知道那里有一个数组。我们可以使用数组、集合、列表或数据库(最常见)。关键是调用这些函数的代码只适用于 Library 的接口(不是文字 Java 接口,而是 Library 的方法签名)。这也是一个更高级别的接口。我们不用担心遍历书籍、执行 for 循环、if 语句等。我们只调用一个方法,说“嘿,在图书馆中找到这本书的书名”。这是怎么做的,我们不在乎。这是面向对象的基本租户,称为封装,它看似强大。这真的是关于我们如何在我们的计划中委派责任,并向个别班级或班级提供工作的详细信息。如果图书馆只有公共成员(即书籍和 bookCount)或 getter/setter,那么客户端将不会获得任何优势,因为客户端仍然必须完成所有繁重的工作。面向对象的诀窍是弄清楚可以从对象中委托什么,而不会产生问题。这需要练习和经验。

The second thing here is we've separated the presentation from the act of finding a book. The method you wrote assumed the next step which was to print "Hey we found it." However, Library object simply returns the Book to you when it finds it, or null if it didn't. That makes it possible to print to the console, display in a GUI, or serialize it to a JSON stream in a server. The act of finding a book is separate from the visualization. This is another important aspect of programming in general, but some what related to object orientation and encapsulation. This is typically called separation of concerns. The console application has concerns about supporting the UI, and printing the console. While the Library just manages cataloging and managing the book collection. How those details are performed neither cares.

这里的第二件事是我们将演示文稿与寻找书籍的行为分开了。您编写的方法假定下一步是打印“嘿,我们找到了”。但是,Library 对象只是在找到 Book 时将其返回给您,如果没有,则返回 null。这使得打印到控制台、在 GUI 中显示或将其序列化为服务器中的 JSON 流成为可能。找书的行为与可视化是分开的。一般来说,这是编程的另一个重要方面,但有些与面向对象和封装有关。这通常称为关注点分离。控制台应用程序担心支持 UI 和打印控制台。而图书馆只负责编目和管理藏书。如何执行这些细节都不在乎。

In the end Library is a reusable class. We can use it in a console application, desktop, web, or middleware server. More importantly is we can also reuse the calls to findByTitle or addBooks from multiple locations within a single program. Also by putting the methods with the data we create a barrier to where that function can be used. You can't do it anywhere in your program. You have to have a reference to Library. If you don't have reference to a Library instance then you shouldn't be calling it. This can be troublesome to new developers because they lack the experience to properly organize their programs to not get into trouble with this (then they start doing value objects, creating statics, singletons, etc and things turn into a big ball of mud). It's a double edged sword.

最终 Library 是一个可重用的类。我们可以在控制台应用程序、桌面、Web 或中间件服务器中使用它。更重要的是,我们还可以在单​​个程序中从多个位置重用对 findByTitle 或 addBooks 的调用。此外,通过将方法与数据放在一起,我们为可以使用该功能的地方设置了障碍。您不能在程序中的任何地方执行此操作。你必须有一个图书馆的参考。如果您没有对 Library 实例的引用,那么您不应该调用它。这对新开发人员来说可能很麻烦,因为他们缺乏正确组织程序的经验,以免遇到麻烦(然后他们开始做值对象,创建静态,单例等,事情变成了一个大泥球)。这是一把双刃剑。

One more thing I'd like to point out is say we wanted to model two Libraries. We have a Library uptown and downtown, and we want to allow people to check out books from either Library. With OO that's really easy to represent:

我还想指出的另一件事是说我们想要对两个图书馆进行建模。我们在市区和市中心都有一个图书馆,我们希望人们可以从这两个图书馆中的任何一个借书。使用 OO 真的很容易表示:

Library uptown = new Library( 50 );
Library downtown = new Library( 100 );

Now we can check out books from one or the other. And I didn't use statics (i.e. global variables) so reusing that logic is really easy. These are the basics of OO so they are really deep topics. Strange how I can write so much on very simple topics. Anyway I hope this helped you understand your program a little deeper, and see how you can use OO to help you.

现在我们可以从其中一个或另一个中查看书籍。而且我没有使用静态(即全局变量),因此重用该逻辑非常容易。这些是面向对象的基础知识,因此它们是非常深入的主题。奇怪我怎么能在非常简单的主题上写这么多。无论如何,我希望这能帮助您更深入地了解您的程序,并了解如何使用 OO 来帮助您。

回答by Tyler Durden

chubbsondubs came closest to giving a correct answer to this question

chubbsondubs 最接近给出这个问题的正确答案

What he missed is that his algorithm is incorrect because it contains two tests, when only one is needed. The correct code requires only 3 statements and is as follows:

他错过的是他的算法不正确,因为它包含两个测试,而只需要一个。正确的代码只需要3条语句,如下:

   public boolean zLibaryContains( String title ) {
       books[bookCount] = title;
       int xBook = 0;
       while( true )
           if( books[xBook].getTitle().equals( title ) )
               return xBook != bookCount;
           else xBook++;              
   }

Noticeably smaller and faster than all other solutions. Simplify, simplify, simplify.

明显比所有其他解决方案更小、更快。简化,简化,简化。

Object-oriented code is a crutch to support poor designs that would otherwise be too complex to understand. The goal is write code that is so easy to understand and maintain that OO is unnecessary and would make the program worse. When your program can be improved by adding OO, it means you are doing something wrong to begin with.

面向对象的代码是支持糟糕设计的拐杖,否则这些设计将太复杂而无法理解。目标是编写易于理解和维护的代码,以至于 OO 是不必要的,并且会使程序变得更糟。当您的程序可以通过添加 OO 来改进时,这意味着您一开始就做错了。