强烈推荐一个大神的人工智能的教程:http://www.captainai.net/zhanghan
前言
java8版本是变更最大的一个版本,高效运行事编译器Java虚拟机的出现,使程序员将更多精力放在编写干净,易于维护的代码上,而不用思考如何将每个CPU时钟周期,每字节内存物尽其用。面对大型数据集合,java还欠缺高效的并行操作。java8提供一些新的特性,能够支持代码在多核CPU上高效运行。在了解java的Stream操作前先要搞明白两个概念:惰性求值法和及早求值法。
惰性求值:不会从stream产生新的集合,返回值依旧是一个Stream类型的
及早求值:会从stream流中产生新的集合
如何判断是惰性求值还是及早求值呢?当返回值是一个Stream时,即是惰性求值,当返回值是另一个值或者空时,是及早求值。
Stream流操作
- 先建立一个Student实体
public class Student implements Serializable { private int no; private String id; @Override public String toString() { return "Student{" + "no=" + no + '}'; } public Student(String id, int no) { this.id = id; this.no = no; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } }
2.创建五个对象和一个list
Student stuA = new Student("1",1); Student stuB = new Student("2",2); Student stuC = new Student("3",3); Student stuD = new Student("4",4); Student stuE = new Student("5",5); List<Student> list = new ArrayList<>(); list.add(stuA); list.add(stuB); list.add(stuC); list.add(stuD); list.add(stuE);
3.各种类型的流操作
- 流操作只使用了惰性求值时不会生成新的stream流,也不会输出任何信息
list.stream() .filter(student -> { System.out.println(student.getNo()); return student.getNo() == 1; });
执行一下结果,在流操作内部,我输出了一个student.getNo(),然而在控制台上并没有任何输出信息,filter是一个惰性求值法,因此不会有任何输出信息以。
- 当一个拥有终止操作的流会生成一个新的值,同时也会输出信息
list.stream() .filter(student -> { System.out.println(student.getNo()); return student.getNo() == 1; }).count();
执行结果如下:
- collect从Stream中生成一个新的列表,属于及早求值
List<String> collected = Stream.of("a","b","c") .collect(Collectors.toList()); System.out.println(collected.toString());
执行结果是[a, b, c]
- map将一种类型转换为另一种类型
List<String> collect = Stream.of("a", "b", "hello") .map(string -> string.toUpperCase()) .collect(Collectors.toList()); System.out.println(collect.toString());
执行结果是[A, B, HELLO]
- flatMap将多个stream流连接成一个Stream流,然后再进行流操作
List<Integer> collect1 = Stream.of(Arrays.asList(1, 2), Arrays.asList(3, 4)) .flatMap(numbers -> numbers.stream()) .collect(Collectors.toList()); System.out.println(collect1.toString());
执行结果是[1, 2, 3, 4]
- max和min 求最大最小值,返回的是一个Optional对象,通过get方法取回,Optional会在之后分析
Integer integer = Stream.of(1, 2, 3, 4) .min(Comparator.comparing(r -> r.intValue())) .get(); System.out.println(integer);
执行结果是1,即求得的最小值是1
- reduce执行加减乘除等操作
Integer reduce = Stream.of(1, 2, 3) .reduce(0, (acc, element) -> acc - element); System.out.println(reduce);
执行结果为-6,意思为从0开始计算,让前一个值-后一个值,得到最终结果
举个例子,优化代码
先说明一下,下边的代码中用到的实体我都没有给出来,只要体会一下没用新特性和使用了新特性之后的写法哪个更简单高效
public Set<String> findLongTracks(List<Album> albums){
Set<String> trackNames = new HashSet<>();
for (Album album : albums) {
for (Track track:album.getTrackList()){
if(track.getLength()>60){
String name = track.getName();
trackNames.add(name);
}
}
}
}
上述代码有两层循环,使用java8新特性进行优化:
public Set<String> findLongTracks(List<Album> albums){ return albums.stream() .flatMap(album -> album.getTracks()) .filter(track->track.getLength()>60) .map(track->track.getName()) .collect(Collectors.toSet()); }
Optional
Optional<T>类是一个容器类,代表一个值存在或不存在,开发者对空指针异常可谓是屡见不鲜了,Optional用法可以避免空指针异常。常见的方法如下:
- Optional.of(T t) 创建一个Optional对象
- Optional.empty(T t) 创建一个空的Optional对象
- Optional.ofNullable(T t) 若t不为null,创建Optional实例,否则创建空实例
- isPresent() 判断对象中是否包含值,返回true 或false
- orElse(T t) 若对象包含值,则返回值,否则返回t
- orElseGet(Supplier other) 若对象包含值,则返回该值,否则返回other获取的值
- map(Function f) 如果有值,则对该值进行处理,返回结果Optional对象,否则返回Optional.empty()
- flatMap(Function mapper) 要求返回值必须是Optional