开篇

放假前从学校图书馆中借来一本书,Oracle官方的《精通Lambda表达式:Java多核编程》。

假期已过大半才想起来还没翻上几页,在此先推荐给大家。

此书内容及其简洁干练,如果你对Java语法有基础的认识看起来就会不费劲,唯一的缺点就是代码部分的内容以及排版有些错误,不过瑕不掩瑜,无伤大雅。

这个系列就是我对书中每一小节的一个提炼、总结以及实践,每一个知识点我都会附上自己写的代码,这些代码用来验证所学的知识。

才疏学浅,如果有理解错误之处请指正,欢迎交流讨论。

遍历一个集合

最传统的方法大概是用Iterator,当然我比较Low,习惯用i<arr.size()这类的循环。(现在我用for/in,本质上还是Iterator...)

这一类方法叫做外部迭代,意为显式地进行迭代操作,即集合中的元素访问是由一个处于集合外部的东西来控制的,在这里控制着循环的东西就是迭代器。

书中举的例子是pointList,我在这里把它换成一个电话簿。

public class ContactList extends ArrayList<String>{}

里面存储着String类型的联系人。

for (Iterator<String> contactListIterator = contactList.iterator(); contactListIterator.hasNext(); ) {
    System.out.println(contactListIterator.next());
}

现在我们将这种遍历方式换成内部迭代。

顾名思义,这种方式的遍历将在集合内部进行,我们不会显式地去控制这个循环。

无需关心遍历元素地顺序,我们只需要定义对其中每一个元素进行什么样的操作。注意在这种设定下可能无法直接获取到当前元素的下标。

Java5中引入Collection.forEach(...),对集合中每一个元素应用其行为参数,这个方法是从其父接口Iterable中继承。

现在我们可以去重写forEach方法。

@Override
public void forEach() {
    for(String s : this) {
        System.out.println(s + " is your contact.");
    }
}

这下我们对电话簿调用forEach方法的时候,遍历操作就会在类的内部完成了。

当然这看起来非常傻并且很不灵活。如果我们想把行为作为参数传给forEach呢?

所幸Java8提供了这种可能,这种行为参数叫做Consumer。

public interface Consumer<T> {
    void accept(T t);
}

一个明显的函数式接口,行为定义在accept方法中。

在定义好了我们自己的Consumer之后,现在这样写:

@Override
public void forEach(Consumer<String> c) {
    for(String s : this) {
        c.accept(s);
    }
}

傻的程度减轻了一些,当然还是不够机智。

在这种情况下一个匿名内部类就能搞定问题(Android里面监听器写到手抽...)

contactList.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s + " is your contact.");
    }
});

这下足够简洁,当然聪明的编译器应该能够推断出我们传入forEach方法的只能是一个Consumer并且需要调用的就是Consumer的唯一方法accept,这段代码还有简化的余地。

所以现在需要登场的就是Lambda表达式了。

既然我们的电话簿ContactList本质上是一个ArrayList<String>,那么编译器也一定能推断出Consumer的类型参数标识为String。

所以这下连参数类型都省了。

contactList.forEach(s -> System.out.println(s + " is your contact, again!"));

->前的p为参数名(即String s中的s),->后为方法体,也可以用一个大括号括起来,因为我这里只写了一句所以就没用。

这就是内部迭代和Lambda相结合的终极奥义了。

现在附上测试代码:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.function.Consumer;

public class ContactList extends ArrayList<String> {
    @Override
    public void forEach(Consumer<? super String> action) {
        super.forEach(action);
    }

    public static void main(String[] args) {
        ContactList contactList = new ContactList();
        contactList.add("Foo");
        contactList.add("Bar");
        contactList.add("Nico");

        for (Iterator<String> contactListIterator = contactList.iterator(); contactListIterator.hasNext(); ) {
            System.out.println(contactListIterator.next());
        }

        System.out.println("\n--- Consumer is coming! ---\n");

        contactList.forEach(new ContactAction());
        System.out.println("\n--- Lambda is coming! ---\n");
        contactList.forEach(s -> System.out.println(s + " is your contact, again!"));
    }

    static class ContactAction implements Consumer<String> {
        @Override
        public void accept(String s) {
            System.out.println(s + " is your contact.");
        }
    }
}

以及运行结果:

Foo
Bar
Nico

--- Consumer is coming! ---

Foo is your contact.
Bar is your contact.
Nico is your contact.

--- Lambda is coming! ---

Foo is your contact, again!
Bar is your contact, again!
Nico is your contact, again!

初探Lambda表达式/Java多核编程【0】从外部迭代到内部迭代的更多相关文章

  1. 初探Lambda表达式/Java多核编程【1】从集合到流

    从集合到流 接上一小节初探Lambda表达式/Java多核编程[0]从外部迭代到内部迭代,本小节将着手使用"流"这一概念进行"迭代"操作. 首先何为" ...

  2. 初探Lambda表达式/Java多核编程【2】并行与组合行为

    今天又翻了一下书的目录,第一章在这之后就结束了.也就是说,这本书所涉及到的新的知识已经全部点到了. 书的其余部分就是对这几个概念做一些基础知识的补充以及更深层次的实践. 最后两个小节的内容较少,所以合 ...

  3. 初探Lambda表达式/Java多核编程【3】Lambda语法与作用域

    接上一篇:初探Lambda表达式/Java多核编程[2]并行与组合行为 本节是第二章开篇,前一章已经浅显地将所有新概念点到,书中剩下的部分将对这些概念做一个基础知识的补充与深入探讨实践. 本章将介绍L ...

  4. 初探Lambda表达式/Java多核编程【4】Lambda变量捕获

    这周开学,上了两天感觉课好多,学校现在还停水,宿舍网络也还没通,简直爆炸,感觉能静下心看书的时间越来越少了...寒假还有些看过书之后的存货,现在写一点发出来.加上假期两个月左右都过去了书才看了1/7都 ...

  5. Lambda&Java多核编程-5-函数式接口与function包

    从前面的总结中我们知道Lambda的使用场景是实现一个函数式接口,那么本篇就将阐述一下何为函数式接口以及Java的function包中提供的几种函数原型. 函数式接口 早期也叫作SAM(Single ...

  6. Lambda&Java多核编程-6-方法与构造器引用

    在Lambda&Java多核编程-2-并行与组合行为一文中,我们对Stream<Contact>里的每一位联系人调用call()方法,并根据能否打通的返回结果过滤掉已经失效的项. ...

  7. Lambda表达式和函数式编程

    Lambda表达式和函数式编程 https://www.cnblogs.com/bigbigbigo/p/8422579.html https://www.runoob.com/java/java8- ...

  8. Lambda&Java多核编程-7-类型检查

    本篇主要介绍Lambda的类型检查机制以及周边的一些知识. 类型检查 在前面的实践中,我们发现表达式的类型能够被上下文所推断.即使同一个表达式,在不同的语境下也能够被推断成不同类型. 这几天在码一个安 ...

  9. Lambda 表达式(C# 编程指南) 微软microsoft官方说明

    Visual Studio 2013 其他版本 Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数. 通过使用 lambda 表达式,可以写入可作为参数传递或作为函数调用值返回的本地 ...

随机推荐

  1. Spring的5种事物配置方式

    Spring事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之间对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的事务配置只 ...

  2. mssql数据库syscolumns表中xtype列

    xtype    类型34 image35 text36 uniqueidentifier48 tinyint52 smallint56 int58 smalldatetime59 real60 mo ...

  3. openstack controller ha测试环境搭建记录(八)——配置nova(控制节点)

    在任一节点创建nova用户:mysql -u root -p CREATE DATABASE nova;GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'localh ...

  4. SQL 复习二(数据查询语言)

    1.1 数据查询语言 DQL就是数据查询语言,数据库执行DQL语句不会对数据进行改变,而是让数据库发送结果集给客户端. 语法: SELECT selection_list /*要查询的列名称*/ FR ...

  5. (简单) POJ 3368 Frequent values,RMQ。

    Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In ad ...

  6. 计算器之webservice实现

    以下是本人原创,如若转载和使用请注明转载地址.本博客信息切勿用于商业,可以个人使用,若喜欢我的博客,请关注我,谢谢!博客地址 一.根据我的上一篇博客 MyEclipse构建Web Service(Xf ...

  7. TCP/IP协议头部结构体(网摘小结)(转)

    源:TCP/IP协议头部结构体(网摘小结) TCP/IP协议头部结构体(转) 网络协议结构体定义 // i386 is little_endian. #ifndef LITTLE_ENDIAN #de ...

  8. Hibernate 中对象关系映射(ObjectRelationMapping)

    1.什么是对象关系映射? 解析:对象-关系映射(Object Relational Mapping,简称ORM,对象关系映射)是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术. 简单的说, ...

  9. Python3基础 setdefault() 根据键查找值,找不到键会添加

    镇场诗: 诚听如来语,顿舍世间名与利.愿做地藏徒,广演是经阎浮提. 愿尽吾所学,成就一良心博客.愿诸后来人,重现智慧清净体.-------------------------------------- ...

  10. android入门,activity跳转,并传递message

    首先是布局文件,如下: activity_main.xml <?xml version="1.0" encoding="utf-8"?> <L ...