龙空技术网

For循环和While循环之流的终结

读芯术 247

前言:

此刻你们对“java for循环结束本次循环”可能比较看重,大家都想要学习一些“java for循环结束本次循环”的相关文章。那么小编在网上收集了一些关于“java for循环结束本次循环””的相关资讯,希望姐妹们能喜欢,你们快快来了解一下吧!

全文共3806字,预计学习时长10分钟

图源:unsplash

循环语句是编程的基本组成部分。列表中的每一项都有用处,读取输入,直到输入结束,在屏幕上放置n个输入框。每当看到PR中的代码添加了循环语句,我都怒不可遏。现在我必定仔细检查代码,确保循环可以终止。

我希望所有运行良好的语句库中都看不到循环语句的踪影,但仍然有一些悄悄混进来,所以我想告诉大家如何消除循环语句。

让循环语句终结的关键是函数式编程。只需提供要在循环中执行的代码以及循环的参数(需要循环的内容)即可。我用Java作示范语言,但其实许多语言都支持这种类型的函数式编程,这种编程可以消除代码中的循环。

最简单的情况是对列表中的每个元素执行操作。

List<Integer> list = List.of(1, 2, 3);// bare for loop. for(int i : list) {   System.out.println("int = "+ i);}// controlled for eachlist.forEach(i -> System.out.println("int = " + i));

在这种最简单的情况下,无论哪种方法都没有太大优势。但第二种方法可以不使用bare for循环,而且语法更简洁。

我觉得forEach语句也有问题,应该只应用于副作用安全的方法。我所说的安全副作用是指不改变程序状态。上例只是记录日志,因此使用无碍。其他有关安全副作用的示例是写入文件、数据库或消息队列。

不安全的副作用会更改程序状态。下面为示例及其解决方法:

// bad side-effect, the loop alters sumint sum = 0;for(int i : list) {    sum += i;}System.out.println("sum = " + sum);// no side-effect, sum iscalculated by loopsum = list       .stream()       .mapToInt(i -> i)       .sum();System.out.println("sum = " + sum);

另一个常见的例子:

// bad side-effect, the loop alters list2List<Integer> list2 = new ArrayList<>();for(int i : list) {   list2.add(i);}list2.forEach(i -> System.out.println("int = " + i));// no sideeffect, the second list is built by the looplist2 = list         .stream()         .collect(Collectors.toList());list2.forEach(i -> System.out.println("int = " + i));

当你需要处理列表项方法中的索引时就会出现问题,但可以解决,如下:

// bare for loop with index:for(int i = 0; i < list.size(); i++) {    System.out.println("item atindex "       + i       + " = "       + list.get(i));}// controlled loop with index:IntStream.range(0, list.size())   .forEach(i ->System.out.println("item at index "    + i    + " = "    + list.get(i)));

老生常谈的问题:读取文件中的每一行直到文件读取完毕如何解决?

BufferedReader reader = new BufferedReader(       new InputStreamReader(      LoopElimination.class.getResourceAsStream("/testfile.txt")));// while loop with clumsy looking syntaxString line;while((line = reader.readLine()) != null) {   System.out.println(line);}reader = new BufferedReader(       new InputStreamReader(      LoopElimination.class.getResourceAsStream("/testfile.txt")));// less clumsy syntaxreader.lines()   .forEach(l ->System.out.println(l));

应对上述情况有一个非常简便的lines方法,可以返回Stream类型。但是如果一个字符一个字符地读取呢?InputStream类没有返回Stream<Character>的方法。我们必须创建自己的Stream:

InputStream is =   LoopElimination.class.getResourceAsStream("/testfile.txt");// while loop with clumsy looking syntaxint c;while((c = is.read()) != -1) {  System.out.print((char)c);}// But this is even uglierInputStream nis =   LoopElimination.class.getResourceAsStream("/testfile.txt");// Exception handling makes functional programming uglyStream.generate(() -> {   try {      return nis.read();   } catch (IOException ex) {      throw new RuntimeException("Errorreading from file", ex);   }}) .takeWhile(ch -> ch != -1) .forEach(ch ->System.out.print((char)(int)ch));

这种情况下while循环看起来更好。此外,Stream版本还使用了可以返回无限项目流的 generate函数,因此必须进一步检查以确保生成过程终止,这是由于takeWhile方法的存在。

InputStream类存在问题,因为缺少peek 方法来创建可轻松转换为Stream的Iterator。它还会抛出一个检查过的异常,这样函数式编程就会杂乱无章。在这种情况下可以使用while语句让PR通过。

为了使上述问题更简洁,可以创建一个新的IterableInputStream类型,如下:

static class InputStreamIterable implements Iterable<Character> {  private final InputStream is;  public InputStreamIterable(InputStreamis) {    this.is = is;  }  public Iterator<Character>iterator() {     return newIterator<Character>() {                      public boolean hasNext() {           try {             // poor man's peek:             is.mark(1);             boolean ret = is.read() !=-1;             is.reset();             return ret;           } catch (IOException ex) {             throw new RuntimeException(                    "Error readinginput stream", ex);           }        }        public Character next() {           try {             return (char)is.read();           } catch (IOException ex) {             throw new RuntimeException(                   "Error readinginput stream", ex);           }        }     };  }}

这样就大大简化了循环问题:

// use a predefined inputstream iterator:InputStreamIterable it = new InputStreamIterable(    LoopElimination.class.getResourceAsStream("/testfile.txt"));StreamSupport.stream(it.spliterator(), false)   .forEach(ch -> System.out.print(ch));

如果你经常遇到此类while循环,那么你可以创建并使用一个专门的Iterable类。但如果只用一次,就不必大费周章,这只是新旧Java不兼容的一个例子。

图源:unsplash

所以,下次你在代码中写for 语句或 while语句的时候,可以停下来思考一下如何用forEach 或 Stream更好地完成你的代码。

留言点赞关注

我们一起分享AI学习与发展的干货

如转载,请后台留言,遵守转载规范

标签: #java for循环结束本次循环 #c语言退出while循环