一、Lists, Sets, and Maps
list按位置对元素排序,元素x在列表中的位置,也称为其索引。一个列表允许重复的元素。list通过其索引来区分相同的对象。
set是无序无重复集合。与列表不同,set没有其元素的位置概念。集合的实现通常针对搜索进行了优化,所以可以快速找到特定的存储值。
map是一个集合,它根据x的一个属性来存储对象x。这意味着映射中的每个元素都是一个键-值对。键是对象的属性,而值是对象本身。映射允许根据其键快速检索一个值。
二、collection的结构
JCF Iterable<E> 接口定义了迭代存储E类型的元素的集合的方法。Collection接口扩展了可迭代的方法,并添加了许多处理集合的方法。List接口可由所有按位置对其元素进行排序的集合来实现。它定义了按索引添加、删除和检索元素的方法。最后,Set接口作为所有无序集合的接口。Set接口不会向它从集合中继承的方法添加任何方法。
三、Iterable Interface
1、背景知识
我们认为一个lambda表达式是一个对象,就和根据person类创建一个对象一样。那么一个lambda表达式对象的类型怎么确定呢,它属于哪个类呢?
我们定义了一系列接口,虽然接口不能作为一个对象的类名,但是这里我们暂且这么认为,既我们定义的这一系列不同类型的接口对应了不同lambda表达式对象的类型。
The generic interface Function<T, R> takes a parameter of type T and returns a value of type R . A bi-function takes two parameters and returns a value: the generic interface BiFunction<T, U, R> takes two parameters of type T and U , in thatorder, and returns a value of type R .It is useful to have a short hand notation for functional types. We will use the notation T→R for the type Function<T, R> and (T, U)→R for the type BiFunction<T, U, R> . Similar shorthand notation will be used for other functional types.There are also functional interfaces that involve the primitive types int , long , and double . For example, the interface IntFunction<R> is the type int →R, the interface LongFunction<R> is the type long→R, and IntToLongFunction is the type int → long .An operator is a function whose parameters and return value have the same type. A binary operator is an operator that takes two parameters, and a unary operator is an operator that takes a single parameter.Thus BinaryOperator<T> has type (T, T)→T, the interface UnaryOperator<T> has type T→T, and LongUnaryOperator has type long → long .A consumer takes at least one parameter and returns no result. The interface Consumer<T> has type T→ void , while the interface BiConsumer<T, U> has type (T, U)→ void .A supplier is the opposite of a consumer: it takes no parameters and returns a value. The interface Supplier<T> has type ( )→T and IntSupplier has type ( )→ int .A predicate is a function that returns a boolean value. Thus Predicate<T> has type T→ boolean , while BiPredicate<T, U> has type (T, U)→ boolean .
可以看到,我们根据传入参数和传出参数的数量,定义了不同lambda表达式的类型。
2.forEach method
Iterable<E>接口提供了如下方法:
void forEach(Consumer<? super E> action)
这个方法的语义是:forEach方法接受一个Consumer<? super E> action类型的变量,根据刚刚的知识我们知道这个类型的变量是一个lambda表达式,而这个lambda表达式接受一个是E的超类的参数作为lambda表达式的输入,且不返回值。E是接口Iterable<E>中的类型
假设我们有一个 `List<Integer>` 类型的集合 `list`,我们想要对集合中的每个元素执行某个操作,比如将元素打印出来。我们可以使用 `forEach` 方法来遍历集合并对每个元素执行操作,代码如下:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.forEach((Integer n) -> System.out.println(n));
在这个例子中,lambda 表达式【(Integer n) -> System.out.println(n)】的类型是 `Consumer<? super Integer>`,这个lambda表达式接受一个interger类超类的参数作为其参数。
注意,由于 Java 8 的类型推断机制,我们不需要显式地指定参数类型。上面的代码可以简写为:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.forEach(n -> System.out.println(n));
在这个简写的版本中,编译器会根据上下文推断出 lambda 表达式的类型。
3.Iterators
在刚刚的例子中,我们发现for each方法可以对一个集合中的所有元素做相同操作,但是如果我希望对集合中的某些特定元素做不同操作该怎么办呢?
Iterator<E> iterator()
调用这个方法,我们就对集合创建了一个iterator对象(和之前的forEach不同,foreach是对集合本身操作,这个是根据集合本身,创建一个新对象,对新对象操作),这个对象除了包含集合中的内容之外,还包含了对这些新对象的一些操作方法,我们可以对集合中的元素进行精确操作,其包含的方法如下:
例子:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.function.Consumer;
/**
* This program demonstrates Iterators.
*/
public class IteratorDemo {
public static void main(String[] args) {
// Array of names.
String[] names = {"Anna", "Bob", "Carlos", "Debby"};
// Create list and add names.
ArrayList<String> nameList = new ArrayList<>();
for (String name : names) {
nameList.add(name);
}
// Define an action for the "remaining" elements.
Consumer<String> action = x -> {
System.out.printf("%s\n", x);
};
// Get the iterator to the list.
Iterator<String> iter = nameList.iterator();
// Process list elements with the iterator.
while (iter.hasNext()) {
String name = iter.next();
System.out.printf("%s %d\n", name, name.length());
if (name.equals("Bob")) {
// Act differently for names after "Bob".
iter.forEachRemaining(action);
}
}
}
}
Anna 4Bob 3CarlosDebby
这里我们发现,对于bob之后的人,我们做了不一样的操作 。
4.Enhanced For Loop
特别的,我们看一个removeIf的例子:
import java.util.ArrayList;
import java.util.function.Predicate;
/**
* This program demonstrates the Collection removeIf.
*/
public class FilterDemo {
public static void main(String[] args) {
// Array of names.
String[] names = {"Anna", "Bob", "Carlos", "Debby"};
// Create list and add names.
ArrayList<String> nameList = new ArrayList<>();
for (String name : names) {
nameList.add(name);
}
// Use forEach with lambda expression to print.
Predicate<String> filter = x -> x.length() <= 4;
// Remove strings with length at most 4 from nameList
nameList.removeIf(filter);
// Print the array list to show remaining strings.
System.out.println(nameList);
}
}
这个例子中,我们用lambda表达式创建了一个检查谓词(predicate),将这个lambda表达式作为一个参数传入removeIf函数。