Java8是往并行方向走的。由面向对象到函数式编程。
在支持函数式编程的同时还可以支持面向对象的开发。
在JDK1.8里面,接口里面可以有实现方法的!默认方法,default。实现这个接口。
接口里面可以有静态方法
注意Lambda表达式的类型势函数。但是在Java中,Lambda表达式是对象!他们必须依赖于一类特别的对象类型-函数式接口
关于Function接口
public classFunctionTest {public static voidmain(String[] args) {
FunctionTest functionTest= newFunctionTest();//传递行为
System.out.println(functionTest.compute(1, value -> {return 10 *value;}));
}public int compute (int a, Functionfunction){//实现,由调用者去实现之
int result =function.apply(a);returnresult;
}
}
解析:
单独吧Lambda抽取出来:
public classFunctionTest {public static voidmain(String[] args) {//先把Lambda定义好
Function function = value -> value * 2;
FunctionTest functionTest= newFunctionTest();
System.out.println(functionTest.compute(5, function));
}public int compute(int a, Functionfunction){int result =function.apply(a);returnresult;
}
}
多个function之间的串联与先后关系的指定:
public classFunctionTest {public static voidmain(String[] args) {
FunctionTest functionTest= newFunctionTest();
System.out.println(functionTest.compute1(2, value -> value * 3, value -> value *value));
System.out.println(functionTest.compute2(2, value -> value * 3, value -> value *value));
}public int compute1(int a, Function function1, Functionfunction2) {returnfunction1.compose(function2).apply(a);
}public int compute2(int a, Function function1, Functionfunction2) {returnfunction1.andThen(function2).apply(a);
}
}
compose源码:
对比上面的例子,先执行function2 然后将结果赋值给function1去执行
andThen是相反的。
所以,对于 R apply(T t); 要想实现两个输入一个输出,是做不到的。可以通过 BiFunction得到。
public classFunctionTest {public static voidmain(String[] args) {
FunctionTest functionTest= newFunctionTest();
System.out.println(functionTest.compute4(2,3, (value1, value2) -> value1 + value2, value -> value *value));
}public int compute4(int a, int b, BiFunction biFunction, Functionfunction){returnbiFunction.andThen(function).apply(a,b);
}
}
Predicate
filter的参数类型就是Predicate!
函数式编程提供了更高层次的抽象化:
test() 名字都是抽象的,不具体。比较宏观。
public classFunctionTest {public static voidmain(String[] args) {
List list = Arrays.asList(1,2,3,4,5,6,7);
FunctionTest functionTest= newFunctionTest();
functionTest.conditionFilter(list, item-> item % 2 == 0);
}public void conditionFilter(List list, Predicatepredicate){for(Integer integer : list){if(predicate.test(integer)){
System.out.println(integer);
}
}
}
}
对于Predicate的default函数:
public classFunctionTest {public static voidmain(String[] args) {
List list = Arrays.asList(1,2,3,4,5,6,7);
FunctionTest functionTest= newFunctionTest();
functionTest.conditionFilter(list, item-> item % 2 == 0, item -> item < 6);
}public void conditionFilter(List list, Predicate predicate1, Predicatepredicate2){for(Integer integer : list){//and 返回的是Predicate! 所以继续 .test
if(predicate1.and(predicate2).test(integer)){//if (predicate1.or(predicate2).test(integer)){
if (predicate1.negate().test(integer)){ //取反。满足条件后剩下的//如果两个都满足
System.out.println(integer);
}
}
}
}
静态方法: 返回的也是Predicate
作用就是判断两个参数是否相等。
public classFunctionTest {public static voidmain(String[] args) {
FunctionTest functionTest= newFunctionTest();//isEqual传进来的是test 然后和参数 “test”比较
System.out.println(functionTest.isEqual(new Date()).test(newDate()));
}public PredicateisEqual(Object object){returnPredicate.isEqual(object);
}
}
Comparator 还是个函数式接口。里面有好几个函数式接口
结合BinaryOperator
Optional 是个容器,可能包含空值,非空值
public classFunctionTest {public static voidmain(String[] args) {//Optional optional = Optional.empty();
Optional optional = Optional.of("valueTest");
optional.ifPresent(item->System.out.println(item));
System.out.println(optional.orElse("world"));
System.out.println(optional.orElseGet( ()-> "hello"));
}
}
public classFunctionTest {public static voidmain(String[] args) {
Employee employee1= newEmployee();
employee1.setName("123");
Employee employee2= newEmployee();
employee2.setName("456");
Company company= newCompany();
company.setName("c1");
List employees =Arrays.asList(employee1, employee2);
company.setEmployees(employees);
List result =company.getEmployees();//if (result != null){//return result;//}else {//return new ArrayList<>();//}//一行代码搞定
Optional optional =Optional.ofNullable(company);
System.out.println(optional.map( item->item.getEmployees()).orElse(Collections.emptyList()));
}
}
注意 Optional类型,不用做参数类型! 因为没有序列化!
作为返回类型,规避null!
方法引用类似于函数指针。‘’
Remember:
function 接收一个 返回一个
Supplier 只返回不接受
总结方法引用分4类:
1. 类名::静态方法名
2. 引用名(对象名)::实例方法名
3. 类名::实例方法名
4. 构造方法引用:: 类名::new
流有个好处,支持并行化,对一个集合进行迭代,流可以并行,多个线程进行处理。对于多核处理性能大大提升。
public classFunctionTest {public static voidmain(String[] args) {
Stream stream = Stream.of("a", "b", "c", "d");
String[] strings= stream.toArray(length -> newString[length]);
Arrays.asList(strings).forEach(System.out::println);
}
}
改造成Lambda表达式构造函数引用: 通过构造函数引用的方式将数组传递进去
public classFunctionTest {public static voidmain(String[] args) {
Stream stream = Stream.of("a", "b", "c", "d");
String[] strings= stream.toArray(String[]::new);
Arrays.asList(strings).forEach(System.out::println);
}
}
public classFunctionTest {public static voidmain(String[] args) {
Stream stream = Stream.of("a", "b", "c", "d");
List list1 = stream.collect(() -> newArrayList(),
(theList, item)->theList.add(item),
(theList1, theList2)->theList1.addAll(theList2));//方法二
List list2 = stream.collect(LinkedList::new, LinkedList::add, LinkedList::addAll);
list.stream().forEach(System.out::println);
}
}
public classFunctionTest {public static voidmain(String[] args) {
Stream stream = Stream.of("a", "b", "c", "d");
String str=stream.collect(Collectors.joining()).toString();
System.out.println(str);
}
}
flatMap去操作:
public classFunctionTest {public static voidmain(String[] args) {
Stream> listStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));//每个List转成Stream
listStream.flatMap( theList ->theList.stream())
.map( item-> item *item).forEach(System.out::println);
}
}
正确使用Optional:
public classFunctionTest {public static voidmain(String[] args) {
Stream stream =Stream.generate(UUID.randomUUID()::toString);//返回的是个Optional可以调用get方法。 流里面的第一个元素为啥返回Optional。避免异常。如果流里面没有元素呢?规避之
System.out.println(stream.findFirst().get());//如果存在元素的话...
stream.findFirst().ifPresent(System.out::println);//可以创建空的流
Stream stream1 =Stream.empty();
stream1.findFirst().ifPresent(System.out::println);
}
}
public classFunctionTest {public static voidmain(String[] args) {
Stream stream = Stream.iterate(1, item -> item + 2).limit(6);
IntSummaryStatistics summaryStatistics= stream.filter(item -> item > 2)
.mapToInt(item-> item * 2).skip(2).limit(2).summaryStatistics();
System.out.println( summaryStatistics.getMax());
System.out.println( summaryStatistics.getMin());
}
}
例子:Map: 中间操作,延迟操作。遇到终止操作时候才会执行之
public classFunctionTest {public static voidmain(String[] args) {
List list = Arrays.asList("hello", "world", "how are you");
list.stream().map(
item->{
String result= item.substring(0, 1).toUpperCase() + item.substring(1);
System.out.println("----->");returnresult;
}
).forEach( System.out::println);
}
}
Map和flatMap
public static voidmain(String[] args) {
List list = Arrays.asList("hello welcome", "world hello");
//返回的List string类型的数组 四个数组对象不是不同的!
List result = list.stream()
// Stream map(Function super T, ? extends R> mapper);
.map(item -> item.split(" ")).distinct().collect(Collectors.toList());
result.forEach(
item -> Arrays.asList(item).forEach(System.out::println)
);
//flatMap System.out.println("----->flatMap"); List resultFlatMap = list.stream().map(item -> item.split(" "))// Stream flatMap(Function super T, ? extends Stream extends R>> mapper);
//将数组类型 转成 String类型
.flatMap(Arrays::stream) // 接收的是一个数组类型。返回Stream类型。这样返回四个Stream。 调用FlatMap把四个Stream合并成一个!
.distinct().collect(Collectors.toList());
resultFlatMap.forEach(System.out::println);
}
分析 FlatMap将结果打平了,结果放在一个流里面。
上述对于 FlatMap的使用, 首先map映射成字符串数组类型的内容, 然后将字符串数组打平。打平成一个Stream。即: 将 Stream ------> Stream
public classFunctionTest {public static voidmain(String[] args) {
List list1 = Arrays.asList("你好", "哈哈");
List list2 = Arrays.asList("zhangsan", "lisi", "wangwu");
List result = list1.stream().flatMap(item -> list2.stream().map(item2 -> item + " " +item2)).collect(Collectors.toList());
result.forEach(System.out::println);
}
}
Stream:
和迭代器不同的是,Stream可以并行化操作,迭代器只能命令式、串行化操作
当使用串行方式遍历时,每特item读完后再读下一个
使用并行去遍历时,数据会被分成多段,其中每一个都在不同的线程中处理,然后将结果一起输出。
Stream的并行操作依赖于Java7中引入的Fork/Join框架。任务分解成小任务。
集合关注的是数据与数据存储
流关注的是数计算,流与迭代器类似的一点是: 流复发重复使用或者消费的。
中间操作都会返回一个Stream对象,比如 Stream Stream 比如 mapToInt返回 Stream
public class FunctionTest {
public static void main(String[] args) {
Employee employee1 = new Employee("a");
Employee employee2 = new Employee("a");
Employee employee3 = new Employee("b");
Employee employee4 = new Employee("c");
List list = Arrays.asList(employee1, employee2, employee3, employee4);
Map nameCountMap = list.stream().collect(Collectors.groupingBy(Employee::getName, Collectors.counting()));
System.out.println(nameCountMap);
}
}
list.stream().collect(Collectors.groupingBy(Employee::getName, Collectors.averagingDouble(Employee::getScore));
分组:group by
分区: partition by 区别group by 只能分两组 ,比如 true false。 90以上及格,以下不及格
collect是Stream提供的一个方法。Collector作为Collect方法的参数。Collector接口非常重要,分析之:
Collector是一个接口,文档解释“它是一个可变的汇聚操作,将输入元素累积到一个可变的结果容器中;它会在所有元素处理完毕之后,将累积结果转换为一个最终的表示(这是一个可选操作。支持串行并行两种方式执行。
注意: 并行不一定比串行块,因为并行涉及到线程切换。比如cpu 2核的,生成四个线程。势必四个线程去增强这两个核心,会存在上下文切换。
Collectors本身提供了关于Collectors的常见汇聚实现,Collectors本身是一个工厂。
Collector是由四个元素组成的
combiner函数,有四个线程同时去执行,那么就会生成四个部分结果。然后合并成一个。用在并行流的场景。
为了确保串行与并行操作的结果等价性,Collector函数需要满足两个条件,identity(同一性)与associativity(结合性)。
public interface Collector T:集合或者流中的每个元素类型, A可变容器类型, R:结果类型
·
public classFunctionTest {public static voidmain(String[] args) {
Employee employee1= new Employee("a", 12);
Employee employee2= new Employee("a", 23);
Employee employee3= new Employee("b", 43);
Employee employee4= new Employee("c", 34);
List employees =Arrays.asList(employee1, employee2, employee3, employee4);
String collect1= employees.stream().map(Employee::getName).collect(Collectors.joining(","));//连续分组
Map>> collect =employees.stream()
.collect(Collectors.groupingBy(Employee::getScore, Collectors.groupingBy(Employee::getName)));//分区
Map> collect2 = employees.stream().collect(Collectors.partitioningBy(e -> e.getScore() > 3));//连续分区
Map>> collect3 = employees.stream().collect(Collectors.partitioningBy(e -> e.getScore() > 80, Collectors.partitioningBy(e -> e.getScore() > 5)));//综合实战
Map collect4 = employees.stream().collect(Collectors.partitioningBy(employee -> employee.getScore() > 90, Collectors.counting()));
Map collect5 =employees.stream().collect(Collectors.groupingBy(Employee::getName,//收集然后XXX
Collectors.collectingAndThen(Collectors.minBy(Comparator.comparingInt(Employee::getScore)),
Optional::get)));
}
}
排序:
Collector.sort() 本质上是调用 list.sort()
public classFunctionTest {public static voidmain(String[] args) {
List list = Arrays.asList("helloWorld", "nihao", "java");
Collections.sort(list, (item1, item2)-> {return (item1.length() -item2.length());});
System.out.println(list);//当lambda没法推断类型时候,指定下
Collections.sort(list, Comparator.comparingInt((String item) ->item.length()).reversed());
list.sort(Comparator.comparingInt(String::length).reversed());
list.sort(Comparator.comparingInt((String item)->item.length()).reversed());//不区分大小写的排序,两个排序规则. 先升序,然后XXX.两个比较规则,第一个相同就调用第二个方法。
Collections.sort(list, Comparator.comparingInt(String::length).thenComparing(String.CASE_INSENSITIVE_ORDER));
Collections.sort(list, Comparator.comparingInt(String::length).thenComparing( (item1, item2)->item1.toLowerCase().compareTo(item2.toLowerCase())));
Collections.sort(list, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase)));//长度希望等的,才需要进行第二次比较。小写进行比较,小写逆序。
Collections.sort(list, Comparator.comparingInt(String::length).thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder())));
Collections.sort(list, Comparator.comparingInt(String::length).reversed().thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder())));//多级排序
Collections.sort(list, Comparator.comparingInt(String::length).reversed()//相同的(比较结果为0的,继续使用下面的方法)
.thenComparing(Comparator.comparing(String::toLowerCase, Comparator.reverseOrder()))//是否起作用,取决于前面的比较情况结果
.thenComparing(Comparator.reverseOrder()));
}
}
定义实现自己的收集器:
/**
* 1.实现接口时候,要定义好泛型
* 2.
*/
public class MySetCollector implements Collector, Set> {
/**
* 提供一个空的容器,供accumulator 后续方法调用
* @return
*/
@Override
public Supplier> supplier() {
System.out.println("-----> supplier");
return HashSet::new;
}
/**
* 累加器类型的,接收两个参数不返回值
* @return
*/
@Override
public BiConsumer, T> accumulator() {
System.out.println("-----> accumulator");
//通过方法引用的方式返回了一个 BiConsumer 对象
// return Set::add;
return (set, item) -> set.add(item);
}
/**
* 将并行流,多个线程所执行的结果合并起来
* @return
*/
@Override
public BinaryOperator> combiner() {
// 把一个部分结果,添加到另外一个部分结果中
System.out.println("------> combiner");
return (set1, set2) -> {
set1.addAll(set2);
return set1;
};
}
/**
* 多线程情况下,最后一步要执行的。返回最终的结果类型。返回结果容器给用户。
* @return
*/
@Override
public Function, Set> finisher() {
// return t -> t;
return Function.identity();
}
/**
* 返回一个set集合,表示当前的收集器诸多独特性。
* @return
*/
@Override
public Set characteristics() {
System.out.println("----->characteristics");
// 直接返回一个不可变的集合,参数为指定的特性
return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, UNORDERED));
}
public static void main(String[] args) {
List list = Arrays.asList("hello", "world", "welcome", "hello");
Set collect = list.stream().collect(new MySetCollector<>());
System.out.println(collect);
}
}
看下面例子:
public class MySetCollector2 implements Collector, Map>{
@Overridepublic Supplier>supplier() {
System.out.println("supplier invoked");return HashSet::new;
}
@Overridepublic BiConsumer, T>accumulator() {
System.out.println("accumulator invoked");return (set, item) ->{
set.add(item);
};
}
@Overridepublic BinaryOperator>combiner() {
System.out.println("combiner invoked");return (set1, set2) ->{
set1.addAll(set2);returnset1;
};
}
@Overridepublic Function, Map>finisher() {
System.out.println("finisher invoked");return set ->{
Map map = new HashMap<>();
set.stream().forEach(
item->map.put(item, item)
);returnmap;
};
}
@Overridepublic Setcharacteristics() {
System.out.println("characteristics invoked!");returnCollections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));
}public static voidmain(String[] args) {
List list = Arrays.asList("hello", "world", "welcome", "a", "b", "c");
Set set = new HashSet<>();
set.addAll(list);
System.out.println("set"+set);
Map collect = set.stream().collect(new MySetCollector2<>());
System.out.println(collect);
}
}
收集器:
对于Collectors惊天工厂类来说,其实现一共分为两种情况:
通过ColletcorImpl来实现
通过reduceing方法来实现(reducing方法本身又是通过CollectorImpl来实现)
关于toList()
public static Collector>toList() {return new CollectorImpl<>((Supplier>) ArrayList::new, List::add,
(left, right)-> { left.addAll(right); returnleft; },
CH_ID);
}