On Github Halo9Pan / introduction_java8
Cube - Page - Concave - Zoom - Linear - Fade - None - Default
Default - Sky - Beige - Simple - Serif - Night Moon - Solarized
核心概念
如果一个接口定义个唯一一个抽象方法,那么这个接口就成为函数式接口
java.lang.Runnable就是一个函数式接口,因为只有一个一个抽象方法
一个新的Annotation
把它放在一个接口前,表示这个接口是一个函数式接口
加上它的接口不会被编译,除非设法把它变成一个函数式接口
有点像@Override,都是声明了一种使用意图,避免把它用错
@FunctionalInterface public interface Action { void run(String param); default void stop(String param) { } }
函数式编程的融合
Runnable r = () -> System.out.println("Hello lambda!");
static Comparator futureComparator() { Comparator cmp = (x, y) -> (x < y) ? -1 : ((x > y) ? 1 : 0); return cmp; }
static Comparator classicComparator() { Comparator cmp = new Comparator() { @Override public int compare(Integer x, Integer y) { return (x < y) ? -1 : ((x > y) ? 1 : 0); } }; return cmp; }
public class Executor { @FunctionalInterface static interface Action { void run(String s); } void futureExecute(Action action) { action.run("Hello, lambda!"); } void classicExecute() { (new Action() { public void run(String param) { System.out.println(param); } }).run("Goodbye, ugly old code style."); } public static void main(String[] args) { Executor executor = new Executor(); executor.classicExecute(); executor.futureExecute((String param) -> System.out.println(param)); executor.futureExecute(param -> System.out.println(param)); executor.futureExecute(System.out::println); executor.futureExecute(s -> System.out.println("*" + s + "*")); } }
当Lambda表达式访问一个定义在Lambda表达式体外的非静态变量或者对象时,这个Lambda表达式称为“捕获的”
int x = 5; return y -> x + y;
为了保证这个lambda表达式声明是正确的,被它捕获的变量必须是“有效final”的
所以要么它们需要用final修饰符号标记,要么保证它们在赋值后不能被改变
非捕获的lambda只需要计算一次. 然后每次使用到它都会返回一个唯一的实例
捕获的lambda表达式每次使用时都需要重新计算一次,从目前实现来看,很像实例化一个匿名内部类的实例
public interface IAction { void run(); default void init(String param) { System.out.println(param); } }
public class ActionOne implements IAction { public ActionOne() { } @Override public void init(String param) { System.out.println("implement one method"); } @Override public void run() { // TODO Auto-generated method stub } }
public interface IWrong { void run(); default void init(String param) { System.out.println(param); } default int hashCode() { // Error } }
流能够是 串行的 或者 并行的
可以使用其中一种方式开始,然后切换到另外的一种方式
使用stream.sequential()或stream.parallel()来达到这种切换
串行流在一个线程上连续操作
并行流就可能一次出现在多个线程上
List<Person> list = persons.stream().collect(Collectors.toList());
List<Person> filterList = persons.stream().filter(p -> p.name == "Halo").collect(Collectors.toList());
List<Person> list = persons.stream().parallel().collect(Collectors.toList());
filter 排除所有与断言不匹配的元素
map 通过Function对元素执行一对一的转换
flatMap 通过FlatMapper将每个元素转变为无或更多的元素
peek 对每个遇到的元素执行一些操作,主要对调试很有用
distinct 根据.equals行为排除所有重复的元素,这是一个有状态的操作
sorted 确保流中的元素在后续的操作中,按照比较器(Comparator)决定的顺序访问,这是一个有状态的操作
limit 保证后续的操作所能看到的最大数量的元素,这是一个有状态的短路的操作
substream 确保后续的操作只能看到一个范围的(根据index)元素
forEach 对流中的每个元素执行一些操作
toArray 将流中的元素倾倒入一个数组
reduce 通过一个二进制操作将流中的元素合并到一起
collect 将流中的元素倾倒入某些容器,例如一个Collection或Map
min 根据一个比较器找到流中元素的最小值
max 根据一个比较器找到流中元素的最大值
count 计算流中元素的数量
anyMatch 判断流中是否至少有一个元素匹配断言。这是一个短路的操作
allMatch 判断流中是否每一个元素都匹配断言。这是一个短路的操作
noneMatch 判断流中是否没有一个元素匹配断言。这是一个短路的操作
findFirst 查找流中的第一个元素。这是一个短路的操作
findAny 查找流中的任意元素,可能对某些流要比findFirst代价低。这是一个短路的操作