踩坑记录 forEach和for in对比

forEach和for in对比

文章思路来自一次dart的踩坑经历,为了下次使用不再纠结。 既然forEach是基于for in (增强型for循环)的封装,那么 forEach 会比 for in 好用吗?

了解forEach、for in

forEach 和 for in 是通过 Iterator 进行遍历 比较下 forEach 的源码,可以看到 forEach 是基于for in (增强型for循环) 的封装,通过回调的方式执行代码块。那么为什么要做这一层封装呢?

// dart
	void forEach(void f(E element)) {
          
   
	    for (E element in this) f(element);
	  }
// java
	default void forEach(Consumer<? super T> action) {
          
   
	        Objects.requireNonNull(action);
	        for (T t : this) {
          
   
	            action.accept(t);
	        }
	    }

应用场景?哪个好用?

我们来康康使用场景

void fun(List<Element> list) {
          
   
        list.forEach((element) ->{
          
   
            // TODO
            // return; 返回给回调函数,也就是上面源码的f()和action 默认只能为void
            // 并且不能执行break;跳出
        });
    }
void fun(List<Element> list) {
          
   
        for (Element element : list) {
          
   
            // TODO
            // return; 返回到fun函数
      		// 可以执行break;跳出循环
        }
    }

可以看到在功能上,明显for in支持的场景更丰富,那forEach的优势呢? 目前想到的场景是,在单线程模型中(如dart)在回调函数里进行异步请求,并且这些请求可以并发的执行,那么forEach的效率就会优于for in。(不可以并发的请求,谨慎使用,谨防踩坑)

dart 踩坑经历

在 dart 中,异步回调最常用的场景就是 await 等待事件返回,继续执行接下来的代码 下面来看两段代码,两段代码分别在子块中执行异步函数,并等待。那么他们的结果会是一样的吗?

Future<void> test1() async {
          
   
	    print(start);
	    var list = [5,4,3,2,1];
	    list.forEach((element) async {
          
   
	      await futurePrint(element);
	    });
	    print(end);
	}
	//输出
	//start
	//end
	//1
	//2
	//3
	//4
	//5

	Future<void> test2() async {
          
   
	    print(start);
	    var list = [5,4,3,2,1];
	    for(var t in list) {
          
   
	      await futurePrint(t);
	    }
	    print(end);
	}
	//输出
	//start
	//5
	//4
	//3
	//2
	//1
	//end

  	Future<void> futurePrint(int num) async {
          
   
   		await Future.delayed(Duration(seconds: num));
   		print(num);
  	}

结果说明了forEach虽然在子块中添加了await关键字,但是并没有等待,也就是说 子代码块(回调函数)是并行的,而for in则是顺序执行。 那么问题出在哪里了? 我们来看下async关键字的位置 对的,其实for in的await是作用于整个函数的,而forEach里的await是作用于回调函数,也就是源码中的f(E element)。它可以保证在整个回调函数里的执行顺序是有序的。

经验分享 程序员 微信小程序 职场和发展