Java8必知必会
Java SE 8添加了2个对集合数据进行批量操作的包: java.util.function 包以及 java.util.stream 包。 流(stream)就如同迭代器(iterator),但附加了许多额外的功能。
Lambda表达式的语法
基本语法:
(parameters) -> expression或:
(parameters) ->{ statements; }基本lambda例子:集合的forEach(()->{})
// 使用 lambda 表达式以及函数操作(functional operation) players.forEach((player) -> System.out.print(player + "; ")); // 在 Java 8 中使用双冒号操作符(double colon operator) players.forEach(System.out::println);使用lambdas 来实现 Runnable接口 的示例:
// 1.1使用匿名内部类 new Thread(new Runnable() { @Override public void run() { System.out.println("Hello world !"); } }).start(); // 1.2使用 lambda expression new Thread(() -> System.out.println("Hello world !")).start(); // 2.1使用匿名内部类 Runnable race1 = new Runnable() { @Override public void run() { System.out.println("Hello world !"); } }; // 2.2使用 lambda expression Runnable race2 = () -> System.out.println("Hello world !"); // 直接调用 run 方法(没开新线程哦!) race1.run(); race2.run();使用Lambdas和Streams
Stream是对集合的包装,通常和lambda一起使用。 使用lambdas可以支持许多操作,如 map, filter, limit, sorted, count, min, max, sum, collect 等等。
System.out.println("给程序员加薪 5% :"); Consumer<Person> giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary()); javaProgrammers.forEach(giveRaise); phpProgrammers.forEach(giveRaise);Consumer:接口,Consumer<T>:Represents an operation that accepts a single input argument and returns no result.
使用过滤器:
System.out.println("下面是月薪超过 $1,400 的PHP程序员:") phpProgrammers.stream() .filter((p) -> (p.getSalary() > 1400)) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));支持多重过滤:
filter(Predicate<? super T> predicate)
return:Stream<T>
作用:Returns a stream consisting of the elements of this stream that match the given predicate.
// 定义 filters Predicate<Person> ageFilter = (p) -> (p.getAge() > 25); Predicate<Person> salaryFilter = (p) -> (p.getSalary() > 1400); Predicate<Person> genderFilter = (p) -> ("female".equals(p.getGender())); System.out.println("下面是年龄大于 24岁且月薪在$1,400以上的女PHP程序员:"); phpProgrammers.stream() .filter(ageFilter) .filter(salaryFilter) .filter(genderFilter) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName())); // 重用filters System.out.println("年龄大于 24岁的女性 Java programmers:"); javaProgrammers.stream() .filter(ageFilter) .filter(genderFilter) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));limit(long maxSize)
return:Stream<T>
作用:Returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
System.out.println("最前面的3个 Java programmers:"); javaProgrammers.stream() .limit(3) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName())); System.out.println("最前面的3个女性 Java programmers:"); javaProgrammers.stream() .filter(genderFilter) .limit(3) .forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));collect:是一个终端操作,它接收的参数是将流中的元素累积到汇总结果的各种方式(称为收集器)
System.out.println("根据 name 排序,并显示前5个 Java programmers:"); List<Person> sortedJavaProgrammers = javaProgrammers .stream() .sorted((p, p2) -> (p.getFirstName().compareTo(p2.getFirstName()))) .limit(5) .collect(toList()); //获取前5个保存到List中 sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName())); System.out.println("根据 salary 排序 Java programmers:"); sortedJavaProgrammers = javaProgrammers .stream() .sorted( (p, p2) -> (p.getSalary() - p2.getSalary()) ) .collect( toList() ); sortedJavaProgrammers.forEach((p) -> System.out.printf("%s %s; %n", p.getFirstName(), p.getLastName()));min和max方法
System.out.println("工资最低的 Java programmer:"); Person pers = javaProgrammers .stream() .min((p1, p2) -> (p1.getSalary() - p2.getSalary())) //返回值:Optional<T> .get(); //A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value. System.out.printf("Name: %s %s; Salary: $%,d.", pers.getFirstName(), pers.getLastName(), pers.getSalary()); System.out.println("工资最高的 Java programmer:"); Person person = javaProgrammers .stream() .max((p, p2) -> (p.getSalary() - p2.getSalary())) .get(); System.out.printf("Name: %s %s; Salary: $%,d.", person.getFirstName(), person.getLastName(), person.getSalary());结合 map 方法,我们可以使用 collect 方法来将我们的结果集放到一个字符串,一个 Set 或一个TreeSet中:
System.out.println("将 PHP programmers 的 first name 拼接成字符串:"); String phpDevelopers = phpProgrammers .stream() .map(Person::getFirstName) .collect(joining(" ; ")); // 在进一步的操作中可以作为标记(token) System.out.println("将 Java programmers 的 first name 存放到 Set:"); Set<String> javaDevFirstName = javaProgrammers .stream() .map(Person::getFirstName) .collect(toSet()); System.out.println("将 Java programmers 的 first name 存放到 TreeSet:"); TreeSet<String> javaDevLastName = javaProgrammers .stream() .map(Person::getLastName) .collect(toCollection(TreeSet::new));Streams 还可以是并行的(parallel)。
System.out.println("计算付给 Java programmers 的所有money:"); int totalSalary = javaProgrammers .parallelStream() .mapToInt(p -> p.getSalary()) .sum();我们可以使用summaryStatistics方法获得stream 中元素的各种汇总数据。 接下来,我们可以访问这些方法,比如getMax, getMin, getSum或getAverage:
//计算 count, min, max, sum, and average for numbers List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); IntSummaryStatistics stats = numbers .stream() .mapToInt((x) -> x) .summaryStatistics(); System.out.println("List中最大的数字 : " + stats.getMax()); System.out.println("List中最小的数字 : " + stats.getMin()); System.out.println("所有数字的总和 : " + stats.getSum()); System.out.println("所有数字的平均值 : " + stats.getAverage());
附:.collect()参数
工厂方法 |
返回类型 |
用于 |
toList |
List<T> |
把流中所有元素收集到List中 |
示例:List<Menu> menus=Menu.getMenus.stream().collect(Collector.toList()) |
||
toSet |
Set<T> |
把流中所有元素收集到Set中,删除重复项 |
示例:Set<Menu> menus=Menu.getMenus.stream().collect(Collector.toSet()) |
||
toCollection |
Collection<T> |
把流中所有元素收集到给定的供应源创建的集合中 |
示例:ArrayList<Menu> menus=Menu.getMenus.stream().collect(Collector.toCollection(ArrayList::new)) |
||
Counting |
Long |
计算流中元素个数 |
示例:Long count=Menu.getMenus.stream().collect(counting); |
||
SummingInt |
Integer |
对流中元素的一个整数属性求和 |
示例:Integer count=Menu.getMenus.stream().collect(summingInt(Menu::getCalories)) |
||
averagingInt |
Double |
计算流中元素integer属性的平均值 |
示例:Double averaging=Menu.getMenus.stream().collect(averagingInt(Menu::getCalories)) |
||
Joining |
String |
连接流中每个元素的toString方法生成的字符串 |
示例:String name=Menu.getMenus.stream().map(Menu::getName).collect(joining(“, ”)) |
||
maxBy |
Optional<T> |
一个包裹了流中按照给定比较器选出的最大元素的optional |
示例:Optional<Menu> fattest=Menu.getMenus.stream().collect(maxBy(Menu::getCalories)) |
||
minBy |
Optional<T> |
一个包裹了流中按照给定比较器选出的最大元素的optional |
示例: Optional<Menu> lessest=Menu.getMenus.stream().collect(minBy(Menu::getCalories)) |
||
Reducing |
归约操作产生的类型 |
从一个作为累加器的初始值开始,利用binaryOperator与流中的元素逐个结合,从而将流归约为单个值 |
示例:int count=Menu.getMenus.stream().collect(reducing(0,Menu::getCalories,Integer::sum)); |
||
collectingAndThen |
转换函数返回的类型 |
包裹另一个转换器,对其结果应用转换函数 |
示例:Int count=Menu.getMenus.stream().collect(collectingAndThen(toList(),List::size)) |
||
groupingBy |
Map<K,List<T>> |
根据流中元素的某个值对流中的元素进行分组,并将属性值做为结果map的键 |
示例:Map<Type,List<Menu>> menuType=Menu.getMenus.stream().collect(groupingby(Menu::getType)) |
||
partitioningBy |
Map<Boolean,List<T>> |
根据流中每个元素应用谓语的结果来对项目进行分区 |
示例:Map<Boolean,List<Menu>> menuType=Menu.getMenus.stream().collect(partitioningBy(Menu::isType)); |