Lambda&Stream 学习

270

Java 8的一个大亮点是引入Lambda表达式和Stream,使用它设计的代码会更加简洁

特性:

  • 函数式编程
  • 参数类型自动推断
  • 代码量少,简洁
  • 函数式接口:只有一个抽象方法(Object类中的方法除外)的接口是函数式接口
    • java.util.function 包下
    • Supplier : 输出
    • Consumer : 输入
    • BiConsumer : 两个输入
    • Function : 一个输入, 一个输出(一般不同类型)
    • UnaryOperator : 一个输入, 一个输出(相同类型)
    • BiFunction : 两个输入,一个输出(一般不同类型)
    • BinaryOperator : 两个输入,一个输出(相同类型)

格式:

(Object ...args) -> expr

方法的引用

函数式接口:

public class Test {
    public static void main(String[] args) throws Exception {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("测试线程");
            }
        }).start();


        new Thread(() -> {
            System.out.println("lambda测试线程");
        }).start();

        /*-------------------------------------*/

        List<String> list = Arrays.asList("aa", "bbb", "ccc", "ddddd");
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.length() - o2.length();
            }
        });

        System.out.println(list.toString());

        Collections.sort(list, (a,b)-> b.length() - a.length());
        System.out.println(list.toString());

        /*--------------------------------*/
        Supplier<String> stringSupplier = (Supplier<String>)() -> "哈哈";
        String s = stringSupplier.get();
        System.out.println(s);

        /*-------------------------------*/
        //无参无返回值
        Runnable r = () -> {
            System.out.println("hello");
        };

        r.run();
        /*--------------------------------*/
        //无参有返回值
        Callable c = new Callable() {
            @Override
            public Object call() throws Exception {
                return "hello";
            }
        };

        Callable c1 = () -> {
            return "hello";
        };

        Callable c2 = () -> "hello";

        System.out.println(c.call());
        System.out.println(c1.call());
        System.out.println(c2.call());
        /*------------------------------------*/
        //有参有返回值
        Function<Integer, Integer> f = a -> {
            int count = 0;
            for (int i = 0; i <= a; i++) {
                count += i;
            }
            return count;
        };

        System.out.println(f.apply(10));

        BiFunction<Integer, Integer, Integer> bf = (a, b) -> a + b;

        System.out.println(bf.apply(10, 20));
        /*--------------------------*/



    }
}

方法引用:

public class FuncTest {
    public static void main(String[] args) {
        //静态方法引用
        Function<String, String> f = a -> Fun.staticUp(a);
        Function<String, String> f1 = Fun::staticUp;

        System.out.println("大写:" + f.apply("aaaaa"));
        System.out.println("大写:" + f1.apply("bbbbb"));

        //实例方法引用
        Function<String, String> f2 = a -> new Fun().up(a);
        Function<String, String> f3 = new Fun()::up;

        System.out.println("大写:" + f2.apply("ccccc"));
        System.out.println("大写:" + f3.apply("ddddd"));

        //对象方法引用
        BiFunction<Fun, String, String> f4 = (fun, a) -> new Fun().upCase(a);
        BiFunction<Fun, String, String> f5 = Fun::upCase;

        System.out.println("大写:" + f4.apply(new Fun(), "eeee"));
        System.out.println("大写:" + f5.apply(new Fun(), "ffff"));

        //构造方法引用
        Supplier<Fun> s = () -> new Fun();
        Supplier<Fun> s1 = Fun::new;
        Supplier<List> s2 = ArrayList::new;

        s.get();
        s1.get();
        s2.get();

    }
}

class Fun{
    public static String staticUp(String a){
        return a.toUpperCase();
    }

    public String up(String a){
        return a.toUpperCase();
    }

    public String upCase(String a){
        return a.toUpperCase();
    }

    public Fun(){
        System.out.println("new Fun()");
    }
}

Stream特性

  • 不是数据结构,没有内部存储
  • 不支持索引访问
  • 延迟计算
  • 支持并行
  • 很容易生成数组或集合(List、set)
  • 支持过滤、查找、转换、汇总、聚合等操作

public class StreamTest {
    //数组
    static void gen1(){
        String[] arr = {"a","b","c","d"};
        Stream<String> stream = Stream.of(arr);
    }
    //集合
    static void gen2(){
        List<String> list = Arrays.asList("a", "b", "c", "d");
        Stream<String> stream = list.stream();
    }
    //generate
    static void gen3(){
        Stream<Integer> stream = Stream.generate(() -> 1);
        stream.limit(10).forEach(System.out::println);

    }
    //iterate
    static void gen4(){
        Stream<Integer> stream = Stream.iterate(1, x -> 1);
        stream.limit(10).forEach(System.out::println);
    }
    //其它api
    static void gen5(){
        String str = "qwer";
        IntStream intStream = str.chars();

        //intStream.forEach(x -> System.out.println(x));
        intStream.forEach(System.out::println);
    }
    //获取偶数
    static void gen6(){
        Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream();
        Stream<Integer> stream1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream();
        stream.filter(x -> x%2 == 0).forEach(System.out::println);

        int sum = stream1.filter(x -> x % 2 == 0).mapToInt(x -> x).sum();
        System.out.println("偶数和:" + sum);
    }
    //排序查找
    static void gen7(){
        Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9).stream();

        Optional<Integer> any = stream.filter(x -> x % 2 == 0).sorted((a, b) -> b - a).findAny();
        System.out.println(any.get());
    }
    //1-50 偶数存入新的list
    static void gen8(){
        List<Integer> list = Stream.iterate(1, x -> x + 1).limit(50).filter(x -> x % 2 == 0).collect(Collectors.toList());

        System.out.println(list);
    }
    //去重
    static void gen9(){
        Stream<Integer> stream = Arrays.asList(2, 2, 3, 5, 5, 6, 7, 3, 9).stream();
        Stream<Integer> stream1 = Arrays.asList(2, 2, 3, 5, 5, 6, 7, 3, 9).stream();
        stream.distinct().forEach(System.out::println);

        Set<Integer> set = stream1.collect(Collectors.toSet());
        System.out.println(set);
    }
    //字符串分隔,转成数字求和
    static void gen10(){
        String str = "9,8,7,6";

        int sum = Stream.of(str.split(",")).mapToInt(x -> Integer.valueOf(x)).sum();
        System.out.println(sum);
    }
    //url参数解析成map
    static void gen11(){
        String str = "id=1&name=tom&password=123456";

        Map<String, String> map = Stream.of(str.split("&")).map(x -> x.split("=")).collect(Collectors.toMap(s -> s[0], s -> s[1]));

        System.out.println(map);
    }

    public static void main(String[] args) {
        //StreamTest.gen1();
        //StreamTest.gen2();
        //StreamTest.gen3();
        //StreamTest.gen4();
        //StreamTest.gen5();
        //StreamTest.gen6();
        //StreamTest.gen7();
        //StreamTest.gen8();
        //StreamTest.gen9();
        //StreamTest.gen10();
        StreamTest.gen11();
    }

}

Lambda 和 Stream 实例:

public class LambdaAndStreamUseTest {

    public static void main(String[] args) {
//        test1();
//        test2();
//        test3();
//        test4();
        test5();
    }

    //取属性
    private static void test1() {
        //id集合
        List<Integer> ids = books().stream().map(Book::getId).collect(Collectors.toList());

        System.out.println("id集合:" + ids);

        //拼接id
        String str = books().stream().map(book -> "'" + book.getId() + "'").collect(Collectors.joining(",", "(", ")"));

        System.out.println("拼接id:" + str);
    }

    //价格排序
    private static void test2() {
        //价格排序
        List<Book> bookList = books().stream().sorted((book1, book2) -> Double.compare(book1.getPrice(), book2.getPrice())).collect(Collectors.toList());

//        bookList.forEach(System.out::println);

        //价格+发布日期排序
        Comparator<Book> priceComparator = Comparator.comparingDouble(Book::getPrice);
        Comparator<Book> dateComparator = Comparator.comparing(Book::getPublishDate);

        List<Book> bookList1 = books().stream().sorted(priceComparator.thenComparing(dateComparator.reversed())).collect(Collectors.toList());
        bookList1.forEach(System.out::println);

    }

    //转map
    private static void test3() {
        Map<Integer, Book> bookMap = books().stream().collect(Collectors.toMap(Book::getId, book -> book));

        bookMap.forEach((key, value) -> System.out.println(key+ ":" + value));

    }
    //所有书的平均价
    private static void test4() {
        Double aDouble = books().stream().collect(Collectors.averagingDouble(Book::getPrice));

        System.out.println("平均价:" + aDouble);
    }
    //分组统计
    private static void test5() {
        Map<Double, Long> map = books().stream().collect(Collectors.groupingBy(Book::getPrice, Collectors.counting()));

        System.out.println("按价格统计:" + map);

        Map<String, Double> map1 = books().stream().collect(Collectors.groupingBy(Book::getBookName, Collectors.summingDouble(Book::getPrice)));

        System.out.println("按书名统计总金额:" + map1);

        Map<String, Double> map2 = books().stream().collect(Collectors.groupingBy(Book::getBookName, Collectors.averagingDouble(Book::getPrice)));

        System.out.println("按书名统计平均价格:" + map2);

        Map<String, Optional<Book>> map3 = books().stream().collect(Collectors.groupingBy(Book::getBookName, Collectors.maxBy(Comparator.comparing(Book::getPrice))));

        System.out.println("每种书最贵的价格:" + map3);

    }



    private static List<Book> books() {
        List<Book> bookList = new ArrayList<>();
        bookList.add(new Book(1, "java", 35d, LocalDate.parse("2019-06-06")));
        bookList.add(new Book(2, "js", 35d, LocalDate.parse("2019-06-06")));
        bookList.add(new Book(3, "php", 55d, LocalDate.parse("2019-03-06")));
        bookList.add(new Book(4, "php", 35d, LocalDate.parse("2019-06-06")));
        bookList.add(new Book(5, "html", 45d, LocalDate.parse("2019-06-06")));
        bookList.add(new Book(6, "spring", 85d, LocalDate.parse("2019-07-06")));
        bookList.add(new Book(7, "mybatis", 45d, LocalDate.parse("2019-06-06")));
        bookList.add(new Book(8, "mysql", 35d, LocalDate.parse("2019-08-06")));
        bookList.add(new Book(9, "spring", 55d, LocalDate.parse("2019-06-01")));
        bookList.add(new Book(10, "springboot", 35d, LocalDate.parse("2019-03-06")));

        return bookList;
    }

}


class Book{
    private Integer id;
    private String bookName;
    private Double price;
    private LocalDate publishDate;

    public Book(Integer id, String bookName, Double price, LocalDate publishDate) {
        this.id = id;
        this.bookName = bookName;
        this.price = price;
        this.publishDate = publishDate;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    public LocalDate getPublishDate() {
        return publishDate;
    }

    public void setPublishDate(LocalDate publishDate) {
        this.publishDate = publishDate;
    }


    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", bookName='" + bookName + '\'' +
                ", price=" + price +
                ", publishDate=" + publishDate +
                '}';
    }
}