您的位置:首页 > 编程语言 > Java开发

Java for Web学习笔记(二四):EL(4)流(Stream)

2016-06-22 22:28 507 查看
这个假期,几家在装修,很吵,说是不准节假日装修,谁理。我觉得中国房子的质量除了90年代的比较差外,很大程度都是装修给搞坏的,这家抡大锤,那家掀地板。就是个碉堡,也有毁坏的日子。

什么是流

对于Collection提供stream,也就是包括List(例如Vector,ArrayList,LinkedList),Set(如HashSet,LinkedHashSet,TreeSet)。流的处理一般如下:



Java 8中的流

在看EL如何支持流,我们先看看Java8中的Stream。

例子一:test0()和test1()是一样的,采用了Lambda表达方式写:

public void test0(){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<Integer> stream = numbers.stream();
stream.filter((x) -> {
return x % 2 == 0;
}).map((x) -> {
return x * x;
}).forEach(System.out::println);
}

public void test1(){
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Stream<Integer> stream = numbers.stream();
stream.filter(x -> x % 2 == 0 )
.map(x -> x * x)
.forEach(System.out::println);
}

例子二:提供一个元素类型比较复杂的例子

public class Book{
private String title;
private String author;
…… getter & setter……
public String toString(){
return "Title("+title+"):Author("+author+")";
}
}

private void testStream(){
Collection<Book> db = new Vector<>();
… 加入元素,从略 …

// 测试1:进行过滤(title中含有A的),然后将过滤后的打印出来
db.stream().filter(x->x.getTitle().contains("A"))
.forEach(System.out::println);

// 测试2:进行过滤(title中含有A的),然后将过滤后的提取某些部分(类型变成String)
// 对于stream进行intermediate操作时,会改变stream,但不会改变原来的数据,即不会改变db,因此我们再次进行db.stream()即可。
db.stream().filter(x->x. getTitle().contains("A"))
.map(x->x.getAuthor()) //相当于 (x)->{return x.getAuthor();}
.forEach(System.out::println);

// 测试3:进行过滤(title中含有A的),然后将过滤后进行重新处理map,将结果输出为Array
// 此处如果采用String[] authors,进行类型转换,会出现错误ClassCastException,应在元素时作转换
Object[] authors = (Object[]) db.stream().filter(x->x. getTitle().contains("A"))
.map(x->x.getAuthor())
.toArray();
for(Object obj :authors){
System.out.println((String)obj);
}
}

EL中的Stream

Intermediate操作

EL3.0支持Stream,但EL 3.0是运行在Java 7中的,因此采用了EL自己实现的Stream API。下面是一个例子:

books.stream().filter(b->b.title == 'Professional Java for Web Applications')
.map(b->{ 'title':b.title, 'author':b.author })
.toList();

filter()

流化后得到Stream<E>,E为元素类型,filter进行过滤,采用Lambda表达式,有一个预设的参数Predicate<E>,返回boolean的判断,只有返回为true的元素才被留在stream中。

distinct()

去除相同的元素。

${[1, 2, 3, 3, 4, 5, 5, 5, 5, 6].stream().distinct().toList()}

forEach()

对每个元素进行操控,不返回值。下面是一个java例子,打印每个元素的平方。

public void test3(){
List<Integer> numbers = Arrays.asList(1, 2, 3, 3, 5, 5, 5, 5, 5, 10);
Stream<Integer> stream = numbers.stream();
stream.distinct()
.forEach(x->System.out.println(x*x));
}

sorted()

排序。对于数字,可以直接使用sorted进行排序,对于一些复制的元素,可以如同 java.util.Comparator<E>进行排序,例如我们已经将request.setAttribute("books", books);在EL如下操作:

${[8, 3, 19, 5, 7, -2, 0].stream().sorted()} <br/>
${books.stream().sorted((b1,b2) -> b1.title.compareTo(b2.title)).toList()}

limit()和substream()

取部分元素,limit是前多少个,substream()是从多少到多少。numbers是[0, 1, 2, 3, 4, 5, 6],EL如下:

${numbers.stream().sorted().limit(3).toList()}  <br/> <!-- 显示[0, 1, 2] -->
${numbers.stream().sorted().substream(2,5).toList()}  <!-- 显示[2, 3, 4] -->

map()

map可以将Stream<A>转换为Stream<B>,例如

<!-- 1、map将Stream<Book>转换为Stream<String> -->
${books.stream().map(b -> b.title).toList()}
<!-- 2、map将Stream<Book>转换为Stream<List<Object>> -->
${books.stream().map(b -> [b.title, b.author]).toList()}
<!-- 3、map转为Stream<Map<Object,Object> -->
${books.stream().map(b -> {"title":b.title, "author":b.author}).toList()}

假设books中含有(Title A, AuthorA)和(Title B,Author B)两本书,则输出:

[Title A, Title B]
[[Title A, Author A], [Title B, Author B]]
[{author=Author A, title=Title A}, {author=Author B, title=Title B}]

我们还可以转成其他的类。

Terminal操作

返回Collection

可以使用toArray和toList返回,返回String[]和List<String>,不过在html中直接输出Object[]会显示一个对象地址,要显示,需要指定具体那个元素。List具有toString(),可以直接显示内容,在之前的例子可以看到。

${books.stream().map(b -> b.title).toArray()}     显示 [Ljava.lang.Object;@d8cd02
${books.stream().map(b -> b.title).toArray()[0]}  显示Title A

可以使用iterator获取一个java.util.Iterator。

使用Aggregate函数

count()可以获取元素的个数,sum()可以求和,可以直接输出结果。

average()要求元素是数,min()和max()要求元素可比较,它们返回都是org.apache.el.stream.Optional的对象Optional<E>,不能直接输出(给出的是地址),需要通过get()获取object的内容。Optional<E>表明可以为null。

${cartItems.stream().map(i -> i.price() * i.quantity()).sum()}
${books.stream().map(b->b.price).min().get()}
${numbers.stream().average().get()}

返回Frist Value

findFirst()返回Optional<E>,第一个元素。

例子

我们以使用前面User类,设置里面元素并request.setAttribute("users", users),具体从略。下面看看jsp的代码。先过滤只剩名字含有“1”的,然后按名字排序,重新组成新的流,返回List,利用List里面的System.out输出结果。

……
<body>
${users.stream().filter(u->fn:contains(u.username,'1'))
.sorted((u1,u2)->(x = u1.lastName.compareTo(u2.lastName);
x == 0 ? u1.firstName.compareTo(u2.firstName):x))
.map(u->{'username':u.username,'first':u.firstName,'last':u.lastName})
.toList()}<br/>
</body>
</html>

相关链接:
我的Professional Java for Web Applications相关文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: