by @王爵nice
学习、思考、运用 java 8
跟上 java 8 - 01
跟上 java 8 - 02
JDK5
跟上 java 8 - 02
JDK6
跟上 java 8 - 02
JDK7
跟上 java 8 - 02
2014年发布的 Java8
跟上 java 8 - 03
跟上 java 8 - 03
命令式编程:命令“机器”如何去做事情(how),这样不管你想要 的是什么(what),它都会按照你的命令实现。
声明式编程:告诉“机器”你想要的是什么(what),
让机器想出如何去做(how)。
跟上 java 8 - 03
什么是函数式?
public static void main(String[] args){
// Calculate total points of all active tasks using sum()
final long totalPointsOfOpenTasks = tasks
.stream()
.filter(task -> task.getStatus() == Status.OPEN)
.mapToInt(Task::getPoints)
.sum();
}
跟上 java 8 - 03
行为参数化
跟上 java 8 - 03
小结
跟上 java 8 - 04
跟上 java 8 - 04
本节大纲
跟上 java 8 - 04
跟上 java 8 - 04
1. (String s) -> s.length()
2. (Project a) -> a.getStars() > 1000
3. (int x, int y) -> {
System.out.println("Result:");
System.out.println(x + y);
}
3. () -> 42
4. () -> 42 (Project p1, Project p2) -> a1.getStars().compareTo(a2.getStars())
Java 8中有效的Lambda表达式
跟上 java 8 - 04
基本语法
(parameters) -> expression
或(请注意语句的花括号)
(parameters) -> { statements; }
跟上 java 8 - 04
哪个不是有效的Lambda表达式?
(1) () -> {}
(2) () -> "Raoul"
(3) () -> {return "Mario";}
(4) (Integer i) -> return "跟上Java8" + i;
(5) (String s) -> {"跟上Java8";}
给你十分钟思考!
跟上 java 8 - 04
在哪里以及如何使用Lambda
List<Project> javaProjects =
filter(data, (Project p) -> "java".equals(p.getLanaguage()));
public interface Predicate<T> {
boolean test (T t);
}
函数式接口
跟上 java 8 - 04
下面哪些接口是函数式接口?
public interface Adder{
int add(int a, int b);
}
public interface SmartAdder extends Adder{
int add(double a, double b);
}
public interface Nothing{
}
跟上 java 8 - 04
Runnable r1 = () -> System.out.println("Hello World 1”); <- 使用Lambda
Runnable r2 = new Runnable(){ <- 使用匿名类
public void run(){
System.out.println("Hello World 2");
}
};
public static void process(Runnable r){
r.run(); <- 打印 Hello World
}
用函数式接口可以干什么呢?
跟上 java 8 - 04
函数描述符
() -> void
(Project, Project) -> int
public void process(Runnable r){
r.run();
}
process(() -> System.out.println("妈妈喊我跟上 Java 8!!"));
跟上 java 8 - 04
(1) execute( () -> {} );
public void execute(Runnable r){
r.run();
}
(2) public Callable<String> fetch() {
return () -> "Fetch 示例";
}
(3) Predicate<Project> p = (Project p) -> p.getStars();
以下哪些是使用lambda表达式的有效方式?
跟上 java 8 - 04
@FunctionalInterface又是怎么回事?
@FunctionalInterface
public interface LearnJava8 {
// 开始学习 Java 8
String go();
}
跟上 java 8 - 04
函数式接口,类型推断 - Predicate
@FunctionalInterface
public interface Predicate<T>{
boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> results = new ArrayList<>();
for(T s: list){
if(p.test(s)){
results.add(s);
}
}
return results;
}
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);
跟上 java 8 - 04
函数式接口,类型推断 - Consumer
@FunctionalInterface
public interface Consumer<T>{
void accept(T t);
}
public static <T> void forEach(List<T> list, Consumer<T> c){
for(T i: list){
c.accept(i);
}
}
// Lambda是 Consumer 中 accept方法的实现
forEach(Arrays.asList(1,2,3,4,5), (Integer i) -> System.out.println(i) );
跟上 java 8 - 04
函数式接口,类型推断 - Function
@FunctionalInterface
public interface Function<T, R>{
R apply(T t);
}
public static <T, R> List<R> map(List<T> list, Function<T, R> f) {
List<R> result = new ArrayList<>();
for(T s: list){
result.add(f.apply(s));
}
return result;
}
// [7, 2, 6]
// lambda是 Function 接口的 apply 方法的 实现
List<Integer> l = map(
Arrays.asList("lambdas","in","action"),
(String s) -> s.length()
);
跟上 java 8 - 05
跟上 java 8 - 05
代码类型检查的过程
List<Project> starProjects = filter(data, (Project p) -> p.getStars() > 1000))
↓
① filter(data, (Project p) -> p.getStars() > 1000))
↓
② filter(List<Project> data, Predicate<Project> predicate)
↓
③ 目标类型
↓
④ boolean test(Project project)
↓
Project -> boolean
跟上 java 8 - 05
lambda 表达式:它没有名称,但有参数列表、函数主体、返回 类型,可能还有一个可以抛出的异常的列表。
lambda 表达式让你可以简洁地传递代码。
函数式接口就是仅仅声明了一个抽象方法的接口。
只有在接受函数式接口的地方才可以使用 lambda 表达式。
lambda 表达式允许你直接内联,为函数式接口的抽象方法提供实现,并且将整个表达式作为函数式接口的一个实例。
小结 ①
跟上 java 8 - 05
Java 8自带一些常用的函数式接口,放在 java.util.function 包里,包括 Predicate<T>、Function<T,R>、Supplier<T>、Consumer<T> 和 BinaryOperator<T>。
Lambda表达式所需要代表的类型称为目标类型。
方法引用让你重复使用现有的方法实现并直接传递它们。
Comparator、Predicate和Function等函数式接口都有几个可以用来结合 lambda 表达式的默认方法。
小结 ②
跟上 java 8 - 06
跟上 java 8 - 06
这个测验里,假设你是Java语言和API的一个负责人。你收到了关于 removeIf 方法的很多请求,希望能为 ArrayList、TreeSet、LinkedList 以及其他集合类型添加 removeIf 方法。
removeIf 方法的功能是删除满足给定断言的所有元素。你的任务是找到添加这个新方法、优化Collection API的最佳途径。
默认方法小测验
跟上 java 8 - 06
关于继承的一些错误观点
✅ 继承不应该成为你一谈到代码复用就试图倚靠的万精油。
跟上 java 8 - 06
解决问题的三条规则
跟上 java 8 - 06
小结
跟上 java 8 - 07
跟上 java 8 - 07
null 带来的种种问题
跟上 java 8 - 07
对Optional对象进行过滤
假设在我们的 User/Address 模型中, User 还提供了一个方法可以取得User对象的年龄,请使用下面的签名改写getStreet方法:
String getStreet(Optional<User> user, int minAge)
找出年龄大于或者等于minAge参数的User所对应的街道地址。
跟上 java 8 - 07
异常 VS Optional
跟上 java 8 - 07
public int readPoint(Properties props, String name) {
String value = props.getProperty(name);
if (value != null) { <- 确保名称对应的属性存在
try {
int i = Integer.parseInt(value); <- 将String属性转 换为数字类型
if (i > 0) { <- 检查返回的数字是否为正数
return i;
}
} catch (NumberFormatException nfe) {
}
}
return 0; <- 如果前述的条件都不满足,返回0
}
以命令式编程的方式从属性中读取point值
跟上 java 8 - 07
小结
跟上 java 8 - 08
跟上 java 8 - 08
List<Project> projects = new ArrayList<>();
for (Project project : projects) {
if(project.getStars() > 1000){
result.add(project);
}
}
Collections.sort(projects, new Comparator<Project>() {
@Override
public int compare(Project o1, Project o2) {
return o1.getStars().compareTo(o2.getStars());
}
});
List<String> names = new ArrayList<>();
for (Project project : projects) {
names.add(project.getName());
}
<- 用累加器筛选元素
<- 用匿名类排序
<- 处理排序后的项目
跟上 java 8 - 08
List<String> names = projects.stream()
.filter(p -> p.getStars() > 1000) <- 筛选 star 大于1000的项目
.sorted(comparing(Project::getStars)) <- 排序
.map(Project::getName) <- 提取项目名称
.collect(toList()); <- 将名称保存在List中
什么是流?
跟上 java 8 - 08
什么是流?
跟上 java 8 - 08
集合与流
跟上 java 8 - 08
集合与流
List<String> names =
projects.stream() <- 建立操作流水线
.filter(p -> p.getStars() > 1000) <- 筛选出star比较高的项目
.map(Project::getName) <- 获取项目名称
.limit(3) <- 只选择前3个
.collect(Collectors.toList()); <- 将结果保存在另一个List中
System.out.println(names); <- 结果是[Blade, Tale, Vue.js]
跟上 java 8 - 08
集合与流
跟上 java 8 - 08
外部迭代与内部迭代
外部迭代:使用Collection接口需要用户去做迭代(比如用for-each)。
内部迭代:操作流水线没有结束
// 外部迭代
for (Project project : projects) {
if (language.equals(project.getLanguage())) {
result.add(project);
}
}
// 内部迭代
List<String> names =
projects.stream()
.filter(p -> p.getStars() > 1000)
.map(Project::getName)
.limit(3)
.collect(Collectors.toList());
跟上 java 8 - 08
集合与流 - 内部迭代和外部迭代
跟上 java 8 - 08
中间操作和终端操作
看代码!
跟上 java 8 - 08
在下列流水线中,你能找出中间操作和收集操作吗?
long count = menu.stream()
.filter(d -> d.getCalories() > 300)
.distinct()
.limit(3)
.count();
跟上 java 8 - 08
使用流
接下来看一个表格 :P
跟上 java 8 - 08
小结
跟上 java 8 - 09
跟上 java 8 - 09
跟上 java 8 - 09
小结
跟上 java 8 - 10
跟上 java 8 - 10
collect是一个终端操作,它接受的参数是将流中元素累积到汇总结果的各种方式(称 为收集器)。
预定义收集器包括将流元素归约和汇总到一个值,例如计算最小值、最大值或平均值。这些收集器总结在Github表格中。
预定义收集器可以用groupingBy对流中元素进行分组,或用partitioningBy进行分区。
收集器可以高效地复合起来,进行多级分组、分区和归约。
小结
跟上 java 8 - 11
现有API存在的问题
跟上 java 8 - 11
JSR310 解决了这些问题
跟上 java 8 - 13
跟上 java 8 - 13
1. 同步阻塞调用
即串行调用,响应时间为所有服务的响应时间总和;
2. 半异步(异步Future)
线程池,异步Future,使用场景:并发请求多服务,总耗时为最长响应时间;提升总响应时间,但是阻塞主请求线程,高并发时依然会造成线程数过多,CPU上下文切换;
3. 全异步(Callback)
Callback方式调用,使用场景:不考虑回调时间且只能对结果做简单处理,如果依赖服务是两个或两个以上服务,则不能合并两个服务的处理结果;不阻塞主请求线程,但使用场景有限。
4. 异步回调
异步回调链式编排(JDK8 CompletableFuture),使用场景:其实不是异步调用方式,只是对依赖多服务的Callback调用结果处理做结果编排,来弥补Callback的不足,从而实现全异步链式调用。
跟上 java 8 - 13