java8新特性学习——lambda && Stream

1.1lambda表达式语法
1.1.1lambda表达式的一般语法

(Type1 param1, Type2 param2, ..., TypeN paramN) -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

这是lambda表达式的完全式语法,后面几种语法是对它的简化。

1.1.2单参数语法

param1 -> {
  statment1;
  statment2;
  //.............
  return statmentM;
}

当lambda表达式的参数个数只有一个,可以省略小括号

例如:将列表中的字符串转换为全小写

List proNames = Arrays.asList(new String[] { "Ni", "Hao","Lambda" });
List lowercaseNames1 = proNames.stream().map(name -> {
    return name.toLowerCase();
}).collect(Collectors.toList());

1.1.3单语句写法
param1 -> statment

当lambda表达式只包含一条语句时,可以省略大括号、return和语句结尾的分号

例如:将列表中的字符串转换为全小写

List proNames = Arrays.asList(new String[] { "Ni", "Hao","Lambda" });

List lowercaseNames2 = proNames.stream()
        .map(name -> name.toLowerCase()).collect(Collectors.toList());

1.1.4方法引用写法
(方法引用和lambda一样是Java8新语言特性,后面会讲到)

Class or instance :: method

例如:将列表中的字符串转换为全小写

List<String> proNames = Arrays.asList(new String[] { "Ni", "Hao","Lambda" });

List<String> lowercaseNames3 = proNames.stream()
        .map(String::toLowerCase).collect(Collectors.toList());

1.2lambda表达式可使用的变量
先举例:
//将为列表中的字符串添加前缀字符串

String waibu = "lambda :";
List proStrs = Arrays.asList(new String[] { "Ni", "Hao","Lambda" });
List execStrs = proStrs.stream().map(chuandi -> {
    Long zidingyi = System.currentTimeMillis();
    return waibu + chuandi + " -----:" + zidingyi;
}).collect(Collectors.toList());
execStrs.forEach(System.out::println);

输出:

lambda :Ni -----:1474622341604
lambda :Hao -----:1474622341604
lambda :Lambda -----:1474622341604

变量waibu :外部变量

变量chuandi :传递变量

变量zidingyi :内部自定义变量

lambda表达式可以访问给它传递的变量,访问自己内部定义的变量,同时也能访问它外部的变量。

不过lambda表达式访问外部变量有一个非常重要的限制:变量不可变(只是引用不可变,而不是真正的不可变)。
java8新特性学习——lambda && Stream_第1张图片
当在表达式内部修改waibu = waibu + ” “;时,IDE就会提示你:

Local variable waibu defined in an enclosing scope must be final or effectively final

编译时会报错。因为变量waibu被lambda表达式引用,所以编译器会隐式的把其当成final来处理。

以前Java的匿名内部类在访问外部变量的时候,外部变量必须用final修饰。现在java8对这个限制做了优化,可以不用显示使用final修饰,但是编译器隐式当成final来处理。

1.3lambda表达式中的this概念
在lambda中,this不是指向lambda表达式产生的那个SAM对象,而是声明它的外部对象。

例如:

public class WhatThis {
     public void whatThis(){
           //转全小写
           List proStrs = Arrays.asList(new String[]{"Ni","Hao","Lambda"});
           List execStrs = proStrs.stream().map(str -> {
                 System.out.println(this.getClass().getName());
                 return str.toLowerCase();
           }).collect(Collectors.toList());
           execStrs.forEach(System.out::println);
     }
     public static void main(String[] args) {
           WhatThis wt = new WhatThis();
           wt.whatThis();
     }
}

输出:
com.wzg.test.WhatThis
com.wzg.test.WhatThis
com.wzg.test.WhatThis
ni
hao
lambda

2.方法引用和构造器引用
本人认为是进一步简化lambda表达式的声明的一种语法糖。

前面的例子中已有使用到: execStrs.forEach(System.out::println);

2.1方法引用
objectName::instanceMethod

ClassName::staticMethod

ClassName::instanceMethod

前两种方式类似,等同于把lambda表达式的参数直接当成instanceMethod|staticMethod的参数来调用。比如System.out::println等同于x->System.out.println(x);Math::max等同于(x, y)->Math.max(x,y)。

最后一种方式,等同于把lambda表达式的第一个参数当成instanceMethod的目标对象,其他剩余参数当成该方法的参数。比如String::toLowerCase等同于x->x.toLowerCase()。

可以这么理解,前两种是将传入对象当参数执行方法,后一种是调用传入对象的方法。

2.2构造器引用
构造器引用语法如下:ClassName::new,把lambda表达式的参数当成ClassName构造器的参数 。例如BigDecimal::new等同于x->new BigDecimal(x)。

3.Stream数据流
3.1 Collection接口的改进

在Iterable接口里面定义有一个简单的输出:default void forEach(Consumer

public class Test {
    public static void main(String[] args) throws Exception {
        List all = new ArrayList();
        all.add("hello");
        all.add("word");
        all.forEach((e) -> {System.out.println(e);});
        all.forEach(System.out :: println);
    }
}

结果:
hello
word
hello
word


在整个Collection接口里面有一个取得Stream接口对象的方法:default Stream stream();
范例:

public class Test {
    public static void main(String[] args) throws Exception {
        List all = new ArrayList();
        all.add("hello");
        all.add("word");
        Stream stream = all.stream();
        System.out.println(stream.count());
    }
}

结果:2
总结:此时取得了一个长度。功能和size()相同,但是它是直接取得了内存中的要分析的数据量。

3.2 Stream操作
Stream相当于是所有数据的流式数据分析工具,既然是数据的分析,那么就需要对数据执行一些简单的操作,例如:可能需要一些过滤,即:满足一些条件之后的数据可以进行分析。
   · 过滤方法:public Stream filter(Predicate

public class Test {
    public static void main(String[] args) throws Exception {
        List all = new ArrayList();
        all.add("java");
        all.add("jsp");
        all.add("servlet");
        all.add("ajax");
        all.add("jquery");
        Stream stream = all.stream().filter((e) -> e.contains("j"));
        System.out.println(stream.count());
    }
}

结果:4
那么只是过滤后显示个数,一点意义都没有,那么最好的做法是将这些过滤后的数据收集起来变为一个新的集合出现,那么就可以使用收集器完成:

     public  R collect(Collectorsuper T,A,R> collector);

这个方法需要使用一个Collector类型,这个类型可以通过Collectors类取得:
     · 收集的结果为List集合:public static Collector

public class Test {
    public static void main(String[] args) throws Exception {
        List all = new ArrayList();
        all.add("java");
        all.add("jsp");
        all.add("servlet");
        all.add("ajax");
        all.add("jquery");
        Stream stream = all.stream().filter((e) -> e.contains("j"));
        List<String> result = stream.collect(Collectors.toList());
        System.out.println(result);
    }
}

结果:
[java, jsp, ajax, jquery]

既然流式处理之中主要是为大数据而生的概念,那么就需要考虑一个数据的分页问题,提供有两个方法:

· 跳过数据量:public Stream skip(long n);

· 取出的数据量:public Stream limit(long maxSize)。

范例:执行分页控制

    public static void main(String[] args) throws Exception {
        List all = new ArrayList();
        all.add("java");
        all.add("jsp");
        all.add("servlet");
        all.add("ajax");
        all.add("jquery");
        all.add("javaScript");
        all.add("json");
        all.add("jdbc");
        Stream stream = all.stream().skip(3).limit(3)
                .map((e) -> e.toLowerCase()).filter((e) -> e.contains("j"));
        List result = stream.collect(Collectors.toList());
        System.out.println(result);
    }

结果:
[ajax, jquery, javascript]
Stream的操作数据流可以结合Lamda更简单处理,但是难度也高。

3.3MapReduce(概念核心)

大数据最本质的做法就是MapReduce,属于数据的两个处理阶段:
· Map阶段:对要参与运算的数据进行提前处理;
  |- 方法:public Stream map(Function

class Orders {
    private String ptitle;
    private double price;
    private int amount;

    public Orders(String ptitle, double price, int amount) {
        super();
        this.ptitle = ptitle;
        this.price = price;
        this.amount = amount;
    }

    public String getPtitle() {
        return ptitle;
    }

    public void setPtitle(String ptitle) {
        this.ptitle = ptitle;
    }

    public double getPrice() {
        return price;
    }

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

    public int getAmount() {
        return amount;
    }

    public void setAmount(int amount) {
        this.amount = amount;
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        List all = new ArrayList();
        all.add(new Orders("平板电脑", 4999, 20));
        all.add(new Orders("手机", 1099, 200));
        all.add(new Orders("笔记本", 9, 80));
        all.add(new Orders("U盘", 99, 180));
        all.add(new Orders("鼠标", 49, 15));
        double allPrice = all.stream()
                .map((obj) -> obj.getPrice() * obj.getAmount())
                .reduce((sum, x) -> sum + x).get();
        System.out.println("商品总销量" + allPrice);
        DoubleSummaryStatistics dss = all.stream()
                .mapToDouble((obj) -> obj.getPrice() * obj.getAmount())
                .summaryStatistics();
        System.out.println("销售总销量" + dss.getCount());
        System.out.println("最高销量" + dss.getMax());
        System.out.println("最低销量" + dss.getMin());
        System.out.println("平均销量" + dss.getAverage());
        System.out.println("总销量" + dss.getSum());
    }
}

结果:

商品总销量339055.0
销售总销量5
最高销量219800.0
最低销量720.0
平均销量67811.0
总销量339055.0

你可能感兴趣的:(java)