函数式编程,Lambda表达式

 Java8最大的变化是引入了函数式编程(functional programming)。具体增加了

  • Lambda表达式(Lambda Experssion)
  • 方法引用(Method Reference)
  • 流(Stream)

本文主要内容为,函数式编程入门和Lambda表达式。

函数式接口:有且只有一个抽象方法的接口。用来表示Lambda表达式的类型。

函数作为一等公民

  • 可以被定义
  • 可以作为参数
  • 可以作为返回值

Java8新增了注解@FunctionalInterface,用于标识一个接口为函数式接口。

接口新特性

  • 接口支持默认方法

支持default关键字

 1 @FunctionalInterface
 2 public interface Consumer<T> {
 3 
 4     void accept(T t);
 5 
 6     default Consumer<T> andThen(Consumer<? super T> after) {
 7         Objects.requireNonNull(after);
 8         return (T t) -> { accept(t); after.accept(t); };
 9     }
10 }
  • 接口支持静态方法

 支持static修饰方法体

1 @FunctionalInterface
2 public interface UnaryOperator<T> extends Function<T, T> {
3 
4     static <T> UnaryOperator<T> identity() {
5         return t -> t;
6     }
7 }

 

Lambda表达式语法:

  • 参数
  • 箭头符号
  • 主体

 

Lambda表达式形式

Runnable noArguments = () -> System.out.println("Hello World"); 无参数,无返回值。
ActionListener oneArgument = event -> System.out.println("button clicked");

有参数,无返回值。只有一个参数可以省略参数括号

Runnable multiStatement = () -> {

  System.out.println("Hello");

  System.out.println(" World");

}

无参数,无返回值。有多个表达式语句,用大括号括起来。

BinaryOperator<Long> add = (x, y) -> x +y;

多个参数,有返回值。参数无显式类型。

BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;

参数显式声明。

 

Java8新增函数式接口

接口 参数 返回类型
Predicate<T> T boolean
Consumer<T> T void
Function<T, R> T R
Supplier<T> None T
UnaryOperator<T> T T
BinaryOperator<T> (T, T) T

其他内置函数式接口

接口 参数 返回类型
Runnable None void
Callable<V> None V
Comparator<T> T int
FileFilter File boolean
Comparable<T> T int

 数据和行为分离

复合Lambda表达式

  • 比较器复合

逆序

1   Comparator.comparing(String::length).reversed();

比较器链

1     Comparator.comparing(String::length).thenComparing(Comparator.naturalOrder());
  • 谓词复合

包含三个方法:negate、and、or。

1     Predicate<Person> isMale = Person::isMale;
2 
3     Predicate<Person> notMale = isMale.negate();
4     Predicate<Person> isMaleAndIsChildren = isMale.and(Person::isChildren);
5     Predicate<Person> isMaleOrIsChildren = isMale.or(Person::isChildren);
  • 函数复合

andThen、compose

 1     UnaryOperator<Integer> u1 = x -> x + 1;
 2     UnaryOperator<Integer> u2 = x -> x * 2;
 3     
 4     // 先执行u1,再执行u2
 5     Function<Integer, Integer> f1 = u1.andThen(u2);
 6     // 先执行u2,再执行u1
 7     Function<Integer, Integer> f2 = u1.compose(u2);
 8      9     f1.apply(1); // (1 + 1) * 2 = 4
10     11     f2.apply(1); // (1 * 2) + 1 = 3

 Java内置函数复合

复杂的复合函数

实现复杂的函数调用

 

代码演示1:

 1     /**
 2      *
 3      * @param treeTableView 树视图
 4      * @param keyMapper 键映射
 5      * @param <T> 泛型类型
 6      * @return 键为外层节点,值为是否展开的映射
 7      */
 8     public static <T> Map<String, Boolean> getExpands(TreeTableView<T> treeTableView, Function<T, String> keyMapper) {
 9         if(treeTableView.getRoot() == null) {
10             return Collections.emptyMap();
11         }
12         Map<String, Boolean> expands = treeTableView.getRoot().getChildren().stream().collect(Collectors.toMap(keyMapper.compose(TreeItem::getValue), TreeItem::isExpanded));
13         return expands;
14     }

代码演示2:

 1      *
 2      * @param treeTableView 树视图
 3      * @param data 泛型数组
 4      * @param classifier 分类符
 5      * @param keyMapper 键映射
 6      * @param clazz 泛型类型
 7      * @param <T> 参数化类型
 8      */
 9     public static <T> void setDataToTreeTableAndKeepSelect(TreeTableView<T> treeTableView, String data, Function<T, String> classifier, Function<T, String> keyMapper, Class<T> clazz, boolean flag) {
10         try {
11             Map<String, Boolean> expands = getExpands(treeTableView, keyMapper);
12             List<T> list = JSONObject.parseArray(data, clazz);
13             Map<String, List<T>> grouped = list.stream().collect(Collectors.groupingBy(classifier, LinkedHashMap::new, Collectors.toList()));
14             TreeItem<T> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
15             TreeItem<T> root = new TreeItem<>(clazz.newInstance());
16             treeTableView.setRoot(root);
17             for (Map.Entry<String, List<T>> entryOuter : grouped.entrySet()) {
18                 Constructor<T> constructor = clazz.getConstructor(String.class, NodeClass.class);
19                 T outer = constructor.newInstance(entryOuter.getKey(), NodeClass.OUTER);
20                 TreeItem<T> outerTreeItem = new TreeItem<>(outer);
21                 root.getChildren().add(outerTreeItem);
22                 outerTreeItem.setExpanded(expands.getOrDefault(entryOuter.getKey(), false));
23                 for (T inner : entryOuter.getValue()) {
24                     TreeItem<T> innerTreeItem = new TreeItem<>(inner);
25                     outerTreeItem.getChildren().add(innerTreeItem);
26                 }
27             }
28             if (flag) {
29                 treeTableView.getRoot().getChildren().forEach(treeItem -> treeItem.setExpanded(true));
30             }
31             treeTableView.setShowRoot(false);
32             treeTableView.getSelectionModel().clearSelection();
33             if (selectedItem == null) {
34                 treeTableView.getSelectionModel().select(0);
35             } else {
36                 treeTableView.getSelectionModel().select(selectedItem);
37             }
38         } catch (Exception e) {
39             e.printStackTrace();
40         }
41     }

 

优化后的版本,移除反射:

  1 import javafx.scene.control.TreeItem;
  2 import javafx.scene.control.TreeTableView;
  3 
  4 import java.util.*;
  5 import java.util.function.BiFunction;
  6 import java.util.function.Function;
  7 import java.util.function.Supplier;
  8 import java.util.stream.Collectors;
  9 
 10 public class Demo {
 11 
 12     public static void main(String[] args) {
 13         /**
 14          * 模拟方法调用
 15          */
 16         setDataToTreeTableAndKeepSelect(new TreeTableView<>(), Arrays.asList(new Entry()), Entry::getClassifier, Entry::getKey, Entry::new, Entry::new, true);
 17     }
 18 
 19     /**
 20      * @param treeTableView 需要挂在的树
 21      * @param data          数据链表
 22      * @param classifier    Entry::getMap 获取分组标识
 23      * @param keyMapper     Entry::getKey 获取唯一键,用来判断节点历史展开情况
 24      * @param biFunction    Entry::new 调用有参构造函数
 25      * @param supplier      Entry::new 调用无参构造函数
 26      * @param flag          节点是否展开
 27      * @param <T>           泛型类
 28      */
 29     public static <T> void setDataToTreeTableAndKeepSelect(TreeTableView<T> treeTableView, List<T> data, Function<T, String> classifier, Function<T, String> keyMapper, BiFunction<String, NodeClass, T> biFunction, Supplier<T> supplier, boolean flag) {
 30         Map<String, Boolean> expands = getExpands(treeTableView, keyMapper);
 31         Map<String, List<T>> grouped = data.stream().collect(Collectors.groupingBy(classifier, LinkedHashMap::new, Collectors.toList()));
 32         TreeItem<T> selectedItem = treeTableView.getSelectionModel().getSelectedItem();
 33         TreeItem<T> root = new TreeItem<>(supplier.get());
 34         treeTableView.setRoot(root);
 35         for (Map.Entry<String, List<T>> entryOuter : grouped.entrySet()) {
 36             T outer = biFunction.apply(entryOuter.getKey(), NodeClass.OUTER);
 37             TreeItem<T> outerTreeItem = new TreeItem<>(outer);
 38             root.getChildren().add(outerTreeItem);
 39             outerTreeItem.setExpanded(expands.getOrDefault(entryOuter.getKey(), false));
 40             for (T inner : entryOuter.getValue()) {
 41                 TreeItem<T> innerTreeItem = new TreeItem<>(inner);
 42                 outerTreeItem.getChildren().add(innerTreeItem);
 43             }
 44         }
 45         if (flag) {
 46             treeTableView.getRoot().getChildren().forEach(treeItem -> treeItem.setExpanded(true));
 47         }
 48         treeTableView.setShowRoot(false);
 49         treeTableView.getSelectionModel().clearSelection();
 50         if (selectedItem == null) {
 51             treeTableView.getSelectionModel().select(0);
 52         } else {
 53             treeTableView.getSelectionModel().select(selectedItem);
 54         }
 55     }
 56 
 57     /**
 58      * @param treeTableView 当前树
 59      * @param keyMapper     键映射器
 60      * @param <T>           泛型类
 61      * @return 当前节点展开、折叠记录
 62      */
 63     public static <T> Map<String, Boolean> getExpands(TreeTableView<T> treeTableView, Function<T, String> keyMapper) {
 64         if (treeTableView.getRoot() == null) {
 65             return Collections.emptyMap();
 66         }
 67         Map<String, Boolean> expands = treeTableView.getRoot().getChildren().stream().collect(Collectors.toMap(keyMapper.compose(TreeItem::getValue), TreeItem::isExpanded));
 68         return expands;
 69     }
 70 
 71     /**
 72      * 树装载的对象类
 73      */
 74     public static class Entry {
 75         private String key;
 76         private String classifier;
 77         private NodeClass nodeClass;
 78 
 79         public Entry() {
 80         }
 81 
 82         public Entry(String key, NodeClass nodeClass) {
 83             this.key = key;
 84             this.nodeClass = nodeClass;
 85         }
 86 
 87         public String getKey() {
 88             return key;
 89         }
 90 
 91         public void setKey(String key) {
 92             this.key = key;
 93         }
 94 
 95         public String getClassifier() {
 96             return classifier;
 97         }
 98 
 99         public void setClassifier(String classifier) {
100             this.classifier = classifier;
101         }
102 
103         public NodeClass getNodeClass() {
104             return nodeClass;
105         }
106 
107         public void setNodeClass(NodeClass nodeClass) {
108             this.nodeClass = nodeClass;
109         }
110     }
111 
112     /**
113      * 三层节点层级
114      */
115     public enum NodeClass {
116         OUTER,
117         MID,
118         INNER;
119     }
120 }

 

 

posted on 2019-07-14 20:44  blouson  阅读(502)  评论(0编辑  收藏  举报