2019.4.17
提炼出了对自己有用的东西,记录了学习过程便于复习。不过例子都来自于参考文章,链接已经在文中贴出。
1. 学习了lamda表达式,简单粗暴的语法糖,被它的功能强大所震撼。
①基础的用法比如匿名函数
//1. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
//2. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
//3. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
②遍历,这里player是迭代的对象名,会根据集合类型自动获取类型,相当于常用for循环里常命名的 i 变量
// 遍历输出
players.forEach((player) -> System.out.print(player + "; "));
③匿名内部类,可以用lambda表达式匿名实现其接口方法(不详述,见下方④举例)
④排序
// 1.1 使用匿名内部类根据 name 排序 players
Arrays.sort(players, new Comparator() {
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2));
}
});
// 1.2 如果使用 lambda expression 排序 players
Comparator sortByName = (String s1, String s2) -> (s1.compareTo(s2));
Arrays.sort(players, sortByName);
// 1.3 也可以采用如下形式:
Arrays.sort(players, (String s1, String s2) -> (s1.compareTo(s2)));
这里就用一个lambda表达式创建了比较器对象,并为其指定行为。排序时传入Arrays.sort()即可
再举一个例子
// 使用匿名内部类根据 name lenght 排序 players
Arrays.sort(players, new Comparator() {
@Override
public int compare(String s1, String s2) {
return (s1.length() - s2.length());
}
});
参考链接:Java中Lambda表达式的使用
2. Consumer接口
它是JAVA 8的新特性,语义上是消费的意思,可以输入某个对象,做一些列和它有关的操作,比如给某个JavaBean(例如Student)的平均分做运算,在控制台输出它的值。消费的概念与消息队列相似,可以根据传入的参数,执行特定的业务功能。
上面的链接讲了批量操作集合对象的例子,在Consumer对象中定义好处理行为即可,如
System.out.println("给程序员加薪 5% :");
Consumer giveRaise = e -> e.setSalary(e.getSalary() / 100 * 5 + e.getSalary());
javaProgrammers.forEach(giveRaise); // 批量操作java程序员集合(List,Set等都可以)
注意Person是一个JavaBean,有工资字段Salary。那么Consumer 则定义了对于每一个输入的Person类对象e,调用 setSalary() 方法,为每个对象的工资字段乘以权值 1.05。最后在forEach中传入消费者对象,则完成了JavaBean集合的批量操作。
参考链接:JAVA8 Consumer接口
3. Stream
Stream是对集合的包装,通常和lambda一起使用,这点让Stream看起来用些类似Iterator。
同时你可以添加过滤器指定哪些对象要批量操作,或者通过max,min等方法获取集合最值以及统计数据。
举例如下
System.out.println("下面是月薪超过 $1,400 的PHP程序员:")
phpProgrammers.stream()
.filter((p) -> (p.getSalary() > 1400))
.forEach((p) -> System.out.printf("%s %s; ", p.getFirstName(), p.getLastName()));
或者用lambda表达式声明多种过滤器对象
// 定义 filters
Predicate ageFilter = (p) -> (p.getAge() > 25);
Predicate salaryFilter = (p) -> (p.getSalary() > 1400);
Predicate 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()));
获取你关心的比较方式中的最值
System.out.println("工资最低的 Java programmer:");
Person pers = javaProgrammers
.stream()
.min((p1, p2) -> (p1.getSalary() - p2.getSalary()))
.get()
也可以把批量处理的结果集输出为字符串,或重组为新的集合
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 javaDevFirstName = javaProgrammers
.stream()
.map(Person::getFirstName)
.collect(toSet());
System.out.println("将 Java programmers 的 first name 存放到 TreeSet:");
TreeSet javaDevLastName = javaProgrammers
.stream()
.map(Person::getLastName)
.collect(toCollection(TreeSet::new));
甚至支持并行和统计
System.out.println("计算付给 Java programmers 的所有money:");
int totalSalary = javaProgrammers
.parallelStream()
.mapToInt(p -> p.getSalary())
.sum();
//计算 count, min, max, sum, and average for numbers
List 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());
4. 还有一种双冒号的写法引文没有专门讲
对于java程序员集合的每个对象,执行命名域System.out的print函数,连变量游标都省略了。
javaProgrammer.foreach(System.out::print);
以及上文例子中有在批处理中,把这个类对象的某个值域单独提出来
String phpDevelopers = phpProgrammers
.stream()
.map(Person::getFirstName)
.collect(joining(" ; ")); // 在进一步的操作中可以作为标记(token)
所以 :: 起到调用函数,和调用值域的作用。