函数式编程详解

概述

函数式编程

  • 即只关注对数据所要进行的操作
  • 包含Lambda表达式(代码简洁 快速开发)、Stream流(处理大数据量下的集合效率高)、Optional(处理空指针异常)、方法引用(即":😊(进一步简化lambda)等
  • 应用场景
    • 实际开发
    • java源码
    • 装~

Lambda表达式

基础

  • 是jdk8中新增的一个语法糖

  • 可以简化某些(并不是全部)匿名内部类的写法

  • 例子

    public static void main(String[] args) {
        //foreachArr(new IntConsumer() {
        //    @Override
        //    public void accept(int value) {
        //        System.out.println(value);
        //    }
        //});
        foreachArr(value -> System.out.println(value));
        
        //int i = calculateNum(new IntBinaryOperator() {
        //    @Override
        //    public int applyAsInt(int left, int right) {
        //        return left + right;
        //    }
        //});
        int i = calculateNum((left, right) -> left + right);
        System.out.println(i);
    }
    
    public static void foreachArr(IntConsumer consumer){
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        for (int i : arr) {
            consumer.accept(i);
        }
    }
    
    public static int calculateNum(IntBinaryOperator operator){
        return operator.applyAsInt(10, 20);
    }
    
  • 省略规则

    • 参数类型可以省略
    • 只有1个参数时小括号可以省略
    • 方法体中只有1句代码时大括号可以省略
    • 方法体中只有1句代码且此代码为return时return可以省略
  • idea提供了匿名内部类与lambda之间的快速切换(alt+enter快捷键)

高级

  • 即方法引用/::

  • 可以再次简化某些(并不是全部)lambda

  • 例子

    //foreachArr(value -> System.out.println(value));
    //类名::方法名
    foreachArr(System.out::println);
    
    //还有对象名::方法名(如name -> sb.append(name) --> sb::append)、类名::方法名、类名::new(如name -> new StringBuilder(name) --> StringBuilder::new)
    
  • idea也提供了lambda与::之间的快速切换(alt+enter快捷键)

Stream流

  • 是用来对大数据量的集合与数组进行快速的操作的

数据准备

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
</dependency>
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Author {

    //id
    private Long id;

    //姓名
    private String name;

    //年龄
    private Integer age;

    //简介
    private String intro;

    //作品
    private List<Book> books;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {

    //id
    private Long id;

    //书名
    private String name;

    //分类
    private String category;

    //评分
    private Integer score;

    //简介
    private String intro;
}
public class App {

    public static void main(String[] args) {

    }

    /**
     * 初始化数据
     * @return
     */
    public static List<Author> getAuthors() {
        Author author1 = new Author(1L,"蒙多",33,"一个从菜刀中明悟哲理的祖安人",null);
        Author author2 = new Author(2L,"亚拉索",15,"狂风也追逐不上他的思考速度",null);
        Author author3 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        Author author4 = new Author(3L,"易",14,"是这个世界在限制他的思维",null);
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L,"刀的两侧是光明与黑暗","哲学,爱情",88,"用一把刀划分了爱恨"));
        books1.add(new Book(2L,"一个人不能死在同一把刀下","个人成长,爱情",99,"讲述如何从失败中明悟真理"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(3L,"那风吹不到的地方","哲学",85,"带你用思维去领略世界的尽头"));
        books2.add(new Book(4L,"吹或不吹","爱情,个人传记",56,"一个哲学家的恋爱观注定很难把他所在的时代理解"));
        books3.add(new Book(5L,"你的剑就是我的剑","爱情",56,"无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));
        books3.add(new Book(6L,"风与剑","个人传记",100,"两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢?"));

        author1.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author1,author2,author3,author4));
        return authorList;
    }
}
public class AppTest {

    private List<Author> authors =  App.getAuthors();

    @Test
    public void test() {
        
    }
}

常用方法

创建stream流对象

//数组
//Arrays.stream()/Stream.of()
int[] arr = {1, 2, 3, 4, 5};
IntStream stream1 = Arrays.stream(arr);
Stream<int[]> stream2 = Stream.of(arr);
//单列集合
//单列集合.stream()
List<Author> authors = getAuthors();
Stream<Author> stream = authors.stream();
//双列集合
//先转换成单列集合
Map<String, Integer> map = new HashMap<>();
map.put("张三", 18);
map.put("李四", 19);
map.put("王五", 20);
Stream<Map.Entry<String, Integer>> stream = map.entrySet().stream();

中间操作

filter()
//过滤流中的元素 只有符合条件的元素还能继续留在流中
//打印所有姓名长度大于1的作家的姓名
//authors.stream()
//        .filter(new Predicate<Author>() {
//            @Override
//            public boolean test(Author author) {
//                return author.getName().length() > 1;
//            }
//        })
//        .forEach(new Consumer<Author>() {
//            @Override
//            public void accept(Author author) {
//                System.out.println(author.getName());
//            }
//        });
authors.stream()
    	.filter(author -> author.getName().length() > 1)
    	.forEach(author -> System.out.println(author.getName()));
map()
//将流中的元素进行转换/计算
//将所有作家的年龄*10
//authors.stream()
//        .map(new Function<Author, Integer>() {
//            @Override
//            public Integer apply(Author author) {
//                return author.getAge() * 10;
//            }
//        })
//        .forEach(new Consumer<Integer>() {
//            @Override
//            public void accept(Integer age) {
//                System.out.println(age);
//            }
//        });
authors.stream()
    	.map(author -> author.getAge() * 10)
    	.forEach(System.out::println);
distinct()
//将流中的元素进行去重处理
//distinct()的去重是基于equals()与hashCode()来判断是否为相同对象的 因此要重写equals()与hashCode()
//打印所有作家的姓名且去重
//authors.stream()
//        .map(new Function<Author, String>() {
//            @Override
//            public String apply(Author author) {
//                return author.getName();
//            }
//        })
//        .distinct()
//        .forEach(new Consumer<String>() {
//            @Override
//            public void accept(String name) {
//                System.out.println(name);
//            }
//        });
authors.stream()
    	.map(Author::getName)
    	.distinct()
    	.forEach(System.out::println);
flatMap()
//将流中的元素进行转换/计算
//map()只能一转一 而flatMap()可以一转多
//打印所有书的分类(形如“个人成长,爱情”的分类要分开)且去重
//authors.stream()
//        .flatMap(new Function<Author, Stream<Book>>() {
//            @Override
//            public Stream<Book> apply(Author author) {
//                return author.getBooks().stream();
//            }
//        })
//        .flatMap(new Function<Book, Stream<String>>() {
//            @Override
//            public Stream<String> apply(Book book) {
//                return Arrays.stream(book.getCategory().split(","));
//            }
//        })
//        .distinct()
//        .forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                System.out.println(s);
//            }
//        });
authors.stream()
    	.flatMap(author -> author.getBooks().stream())
    	.flatMap(book -> Arrays.stream(book.getCategory().split(",")))
    	.distinct()
    	.forEach(System.out::println);
sorted()
//将流中的元素进行排序处理
//空参的sorted()也可以调用 但参数必须实现Comparator/Comparable接口并重写其比较方法
//升序打印所有作家的年龄且去重
//authors.stream()
//        .map(new Function<Author, Integer>() {
//            @Override
//            public Integer apply(Author author) {
//                return author.getAge();
//            }
//        })
//        .distinct()
//        .sorted(new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                return o1 - o2;
//            }
//        })
//        .forEach(new Consumer<Integer>() {
//            @Override
//            public void accept(Integer age) {
//                System.out.println(age);
//            }
//        });
authors.stream()
    	.map(Author::getAge)
    	.distinct()
    	.sorted((o1, o2) -> o1 - o2)
    	.forEach(System.out::println);
limit()
//设置流的最大长度 超出的元素会被丢弃
//打印年龄最大的2个作家的姓名且去重
//authors.stream()
//        .distinct()
//        .sorted(new Comparator<Author>() {
//            @Override
//            public int compare(Author o1, Author o2) {
//                return o2.getAge() - o1.getAge();
//            }
//        })
//        .limit(2)
//        .forEach(new Consumer<Author>() {
//            @Override
//            public void accept(Author author) {
//                System.out.println(author.getName());
//            }
//        });
authors.stream()
    	.distinct()
    	.sorted((o1, o2) -> o2.getAge() - o1.getAge())
    	.limit(2)
    	.forEach(author -> System.out.println(author.getName()));
skip()
//跳过流的前几个元素
//打印除年龄最大的之外的作家的姓名且去重
//authors.stream()
//        .distinct()
//        .sorted(new Comparator<Author>() {
//            @Override
//            public int compare(Author o1, Author o2) {
//                return o2.getAge() - o1.getAge();
//            }
//        })
//        .skip(1)
//        .forEach(new Consumer<Author>() {
//            @Override
//            public void accept(Author author) {
//                System.out.println(author.getName());
//            }
//        });
authors.stream()
    	.distinct()
    	.sorted((o1, o2) -> o2.getAge() - o1.getAge())
    	.skip(1)
    	.forEach(author -> System.out.println(author.getName()));

终结操作

forEach()
  • 遍历流的元素
count()
//获取流的元素个数
//打印书籍的数目且去重
//long count = authors.stream()
//        .flatMap(new Function<Author, Stream<Book>>() {
//            @Override
//            public Stream<Book> apply(Author author) {
//                return author.getBooks().stream();
//            }
//        })
//        .distinct()
//        .count();
long count = authors.stream()
    	.flatMap(author -> author.getBooks().stream())
    	.distinct()
    	.count();
System.out.println(count);
max()/min()
//获取流的元素的最值
//打印所有书籍的最高分与最低分且去重
//Optional<Integer> max = authors.stream()
//        .flatMap(new Function<Author, Stream<? extends Book>>() {
//            @Override
//            public Stream<? extends Book> apply(Author author) {
//                return author.getBooks().stream();
//            }
//        })
//        .distinct()
//        .map(new Function<Book, Integer>() {
//            @Override
//            public Integer apply(Book book) {
//                return book.getScore();
//            }
//        })
//        .max(new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                return o1 - o2;
//            }
//        });
//Optional<Integer> min = authors.stream()
//        .flatMap(new Function<Author, Stream<? extends Book>>() {
//            @Override
//            public Stream<? extends Book> apply(Author author) {
//                return author.getBooks().stream();
//            }
//        })
//        .distinct()
//        .map(new Function<Book, Integer>() {
//            @Override
//            public Integer apply(Book book) {
//                return book.getScore();
//            }
//        })
//        .min(new Comparator<Integer>() {
//            @Override
//            public int compare(Integer o1, Integer o2) {
//                return o1 - o2;
//            }
//        });
Optional<Integer> max = authors.stream()
    	.flatMap(author -> author.getBooks().stream())
    	.distinct()
    	.map(Book::getScore)
    	.max((o1, o2) -> o1 - o2);
Optional<Integer> min = authors.stream()
    	.flatMap(author -> author.getBooks().stream())
    	.distinct()
    	.map(Book::getScore)
    	.min((o1, o2) -> o1 - o2);
System.out.println(max.get());
System.out.println(min.get());
collect()
//将流的元素转换成集合
//将所有作家的姓名汇集成list且去重
//List<String> nameList = authors.stream()
//        .map(new Function<Author, String>() {
//            @Override
//            public String apply(Author author) {
//                return author.getName();
//            }
//        })
//        .distinct()
//        .collect(Collectors.toList());
//将所有书籍的名字汇集成set且去重
//Set<Book> bookSet = authors.stream()
//        .flatMap(new Function<Author, Stream<Book>>() {
//            @Override
//            public Stream<Book> apply(Author author) {
//                return author.getBooks().stream();
//            }
//        })
//        .collect(Collectors.toSet());
//以作家的姓名为key、此作家的书籍(List<Book>)为value汇集成map且去重
//Map<String, List<Book>> map = authors.stream()
//        .distinct()
//        .collect(Collectors.toMap(new Function<Author, String>() {
//            @Override
//            public String apply(Author author) {
//                return author.getName();
//            }
//        }, new Function<Author, List<Book>>() {
//            @Override
//            public List<Book> apply(Author author) {
//                return author.getBooks();
//            }
//        }));
List<String> nameList = authors.stream()
    	.map(Author::getName)
    	.distinct()
    	.collect(Collectors.toList());
Set<Book> bookSet = authors.stream()
    	.flatMap(author -> author.getBooks().stream())
    	.collect(Collectors.toSet());
Map<String, List<Book>> map = authors.stream()
    	.distinct()
    	.collect(Collectors.toMap(Author::getName, Author::getBooks));
System.out.println(nameList);
System.out.println(bookSet);
System.out.println(map);
判断与查找
anyMatch
//判断流的元素是否有任意一个符合条件
//是否有年龄在29岁以上的作家
//boolean b = authors.stream()
//        .distinct()
//        .anyMatch(new Predicate<Author>() {
//            @Override
//            public boolean test(Author author) {
//                return author.getAge() > 29;
//            }
//        });
boolean b = authors.stream()
    	.distinct()
    	.anyMatch(author -> author.getAge() > 29);
System.out.println(b);
allMatch
//判断流的元素是否都符合条件
//是否所有的作家都是成年人
//boolean b = authors.stream()
//        .distinct()
//        .allMatch(new Predicate<Author>() {
//            @Override
//            public boolean test(Author author) {
//                return author.getAge() >= 18;
//            }
//        });
boolean b = authors.stream()
    	.distinct()
    	.allMatch(author -> author.getAge() >= 18);
System.out.println(b);
noneMatch
//判断流的元素是否都不符合条件
//是否所有的作家都不是60岁的老人
//boolean b = authors.stream()
//        .distinct()
//        .noneMatch(new Predicate<Author>() {
//            @Override
//            public boolean test(Author author) {
//                return author.getAge() >= 60;
//            }
//        });
boolean b = authors.stream()
    	.distinct()
    	.noneMatch(author -> author.getAge() >= 60);
System.out.println(b);
findAny
//获取流的任意一个元素
//对于串行流来说获取的是第一个元素 对于并行流来说获取的是随机一个元素
//随机打印一个作家的姓名
//Optional<Author> any = authors.parallelStream()
//        .distinct()
//        .findAny();
//any.ifPresent(new Consumer<Author>() {
//    @Override
//    public void accept(Author author) {
//        System.out.println(author.getName());
//    }
//});
Optional<Author> any = authors.parallelStream()
    	.distinct()
    	.findAny();
any.ifPresent(author -> System.out.println(author.getName()));
findFirst
//获取流的第一个元素
//打印一个作家的姓名
//Optional<Author> any = authors.parallelStream()
//        .distinct()
//        .findFirst();
//any.ifPresent(new Consumer<Author>() {
//    @Override
//    public void accept(Author author) {
//        System.out.println(author.getName());
//    }
//});
Optional<Author> any = authors.parallelStream()
    	.distinct()
    	.findFirst();
any.ifPresent(author -> System.out.println(author.getName()));
reduce
  • 又称为缩减操作
//连续计算流的元素
//计算所有作家的年龄的和
//Integer reduce1 = authors.stream()
//        .distinct()
//        .map(new Function<Author, Integer>() {
//            @Override
//            public Integer apply(Author author) {
//                return author.getAge();
//            }
//        })
//        //identity为初始值 accumulator为计算方式
//        .reduce(0, new BinaryOperator<Integer>() {
//            @Override
//            public Integer apply(Integer result, Integer element) {
//                return result + element;
//            }
//        });
//打印年龄最小的作家的年龄
//Optional<Integer> reduce2 = authors.stream()
//        .distinct()
//        .map(new Function<Author, Integer>() {
//            @Override
//            public Integer apply(Author author) {
//                return author.getAge();
//            }
//        })
//        //若无identity则初始值为流的第一个元素
//        .reduce(new BinaryOperator<Integer>() {
//            @Override
//            public Integer apply(Integer result, Integer element) {
//                return element < result ? element : result;
//            }
//        });
//System.out.println(reduce1);
//reduce2.ifPresent(new Consumer<Integer>() {
//    @Override
//    public void accept(Integer age) {
//        System.out.println(age);
//    }
//});
Integer reduce1 = authors.stream()
    	.distinct()
    	.map(Author::getAge)
    	.reduce(0, (result, element) -> result + element);
Optional<Integer> reduce2 = authors.stream()
    	.distinct()
    	.map(Author::getAge)
    	.reduce((result, element) -> element < result ? element : result);
System.out.println(reduce1);
reduce2.ifPresent(System.out::println);

总结

  • 若无终结操作 则中间操作是不会执行的
  • 若某个流经过了终结操作后则此流就不能够再次使用了
  • 一般的 对流所进行的操作是不会对原数据有所影响的

函数接口

  • 即只有一个抽象方法的接口
    • 接口的抽象方法可省略public/… abstract
  • 通常有@FunctionalInterface注释以声明此接口为函数接口

常见的函数接口

Consumer

@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
}

Function

@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);
}

Predicate

@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
    
    //使用&&拼接条件
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
    
    //使用||拼接条件
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
    
    //对条件取反
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }
}
//打印姓名的长度大于1且为成年人的作家
//authors.stream()
//        .distinct()
//        .filter(new Predicate<Author>() {
//            @Override
//            public boolean test(Author author) {
//                return author.getName().length() > 1;
//            }
//        }.and(new Predicate<Author>() {
//            @Override
//            public boolean test(Author author) {
//                return author.getAge() >= 18;
//            }
//        }))
//        .forEach(new Consumer<Author>() {
//            @Override
//            public void accept(Author author) {
//                System.out.println(author);
//            }
//        });
authors.stream()
    	.distinct()
    	.filter(((Predicate<Author>) author -> author.getName().length() > 1).and(author -> author.getAge() >= 18))
    	.forEach(System.out::println);

Supplier

@FunctionalInterface
public interface Supplier<T> {

    T get();
}

Optional

  • 能防止产生空指针异常

数据准备

  • 与stream流一样

常用方法

创建optional对象

//封装对象
Optional<Author> optional = Optional.ofNullable(authors.get(0));
//封装非null对象
Optional<Author> optional = Optional.of(authors.get(0));
//封装null
Optional<Author> optional = Optional.empty();
//ofNullable()源码
public final class Optional<T> {
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
}

ifPresent

//安全消费值
//在消费值之前会先判断值是否为空
Optional<Author> optional = Optional.ofNullable(null);
optional.ifPresent(System.out::println);
//ifPresent()源码
public final class Optional<T> {
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
}

get

//获取值
//不推荐使用此方法 因为当值为null时会抛出NoSuchElementException
Optional<Author> optional = Optional.ofNullable(null);
Author author = optional.get();
System.out.println(author);
//get()源码
public final class Optional<T> {
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
}

orElseGet

//安全获取值
Optional<Author> optional = Optional.ofNullable(null);
//参数为默认值且当值为null时返回此默认值
Author author = optional.orElseGet(Author::new);
System.out.println(author);
//orElseGet()源码
public final class Optional<T> {
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
}

orElseThrow

//安全获取值
Optional<Author> optional = Optional.ofNullable(null);
//参数为默认异常且当值为null时抛出此默认异常
try {
    Author author = optional.orElseThrow((Supplier<Throwable>) () -> new RuntimeException("获取的数据为null!"));
    System.out.println(author);
} catch (Throwable throwable) {
    throwable.printStackTrace();
}
//orElseThrow()源码
public final class Optional<T> {
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
}

filter

//过滤
//过滤后的数据有可能为null
Optional<Author> optional = Optional.ofNullable(authors.get(0));
optional.filter(author -> author.getAge() >= 100).ifPresent(System.out::println);

isPresent

//判断数据是否为null
Optional<Author> optional = Optional.ofNullable(authors.get(0));
if (optional.isPresent()) {
    System.out.println(optional.get());
}
//isPresent()源码
public final class Optional<T> {
    public boolean isPresent() {
        return value != null;
    }
}

map

//将数据进行转换/计算
Optional<Author> optional = Optional.ofNullable(authors.get(0));
optional.map(Author::getBooks).ifPresent(System.out::println);

Else

  • Stream流中的map()与flatMap()返回的都是Stream<R>流对象 而也有一些方法可以直接返回IntStream、DoubleStream、LongStream等 如mapToInt()、mapToDouble()、mapToLong()、flatMapToInt()、flatMapToDouble()、flatMapToLong()等 而在处理大数据量时使用后者的耗时更短

  • 可以使用parallelStream()/parallel()将串行流转换成并行流(即将串行流的所有元素分成多个数据块并使用不同的线程分别对不同的数据块进行处理)以提高效率

    Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    Arrays.stream(arr)
        	.parallel()
        	//peek()属于中间操作 作用为返回此流 一般用于调试 但因为idea有Stream Trace所以此方法不常用了
        	.peek(i -> System.out.println(i + " " + Thread.currentThread().getName()))
        	.reduce((i1, i2) -> i1 + i2)
        	.ifPresent(System.out::println);
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值