lambda表达式10个示例——学习笔记

摘录:http://www.importnew.com/16436.htmlhtml

一、lambda实现Runnable

复制代码
// Java 8以前:
new Thread(new Runnable() { @Override public void run() {
    System.out.println("Before Java8, too much code for too little to do");
    }
}).start();
复制代码
//Java 8方式:用() -> {}代码块替代了整个匿名类
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();

output:java

too much code, for too little to do
Lambda expression rocks !!

若是你的方法不对参数进行修改、重写,只是在控制台打印点东西的话,那么能够这样写:git

() -> System.out.println("Hello Lambda Expressions");

若是你的方法接收两个参数,那么能够写成以下这样:shell

若是你的方法接收两个参数,那么能够写成以下这样:

二、使用Java 8 lambda表达式进行事件处理

编写事件监听:express

复制代码
// Java 8以前:
JButton show =  new JButton("Show");
show.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) {
    System.out.println("Event handling without lambda expression is boring");
    }
});
复制代码
// Java 8方式:
show.addActionListener((e) -> {
    System.out.println("Light, Camera, Action !! Lambda expressions Rocks");
});

output:编程

too much code, for too little to do
Lambda expression rocks !!

三、使用lambda表达式对列表进行迭代

// Java 8以前:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
    System.out.println(feature);
}
复制代码
// Java 8以后:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));
 
// 使用Java 8的方法引用更方便,方法引用由::双冒号操做符标示, // 看起来像C++的做用域解析运算符
features.forEach(System.out::println);
复制代码

output:微信

Lambdas
Default Method
Stream API
Date and Time API

四、使用lambda表达式和函数式接口Predicate

 java.util.function.Predicate 函数式接口以及lambda表达式,能够向API方法添加逻辑,用更少的代码支持更多的动态行为。网络

复制代码
public static void main(args[]){
    List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");
 
    System.out.println("Languages which starts with J :");
    filter(languages, (str)->str.startsWith("J"));
 
    System.out.println("Languages which ends with a ");
    filter(languages, (str)->str.endsWith("a"));
 
    System.out.println("Print all languages :");
    filter(languages, (str)->true);
 
    System.out.println("Print no language : ");
    filter(languages, (str)->false);
 
    System.out.println("Print language whose length greater than 4:");
    filter(languages, (str)->str.length() > 4);
}
 
public static void filter(List names, Predicate condition) {
    for(String name: names)  {
        if(condition.test(name)) {
            System.out.println(name + " ");
        }
    }
}
复制代码

output:闭包

复制代码
Languages which starts with J :
Java
Languages which ends with a
Java
Scala
Print all languages :
Java
Scala
C++
Haskell
Lisp
Print no language :
Print language whose length greater than 4:
Scala
Haskell
复制代码

better way:app

// 更好的办法
public static void filter(List names, Predicate condition) {
    names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
        System.out.println(name + " ");
    });
}

五、如何在lambda表达式中加入Predicate

java.util.function.Predicate 容许将两个或更多的 Predicate 合成一个。它提供相似于逻辑操做符AND和OR的方法,名字叫作and()、or()和xor(),用于将传入 filter() 方法的条件合并起来。

复制代码
// 甚至能够用and()、or()和xor()逻辑函数来合并Predicate,
// 例如要找到全部以J开始,长度为四个字母的名字,你能够合并两个Predicate并传入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
    .filter(startsWithJ.and(fourLetterLong))
    .forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));
复制代码

也可使用 or() 和 xor() 方法

六、Java 8中使用lambda表达式的Map和Reduce示例

将 costBeforeTax 列表的每一个元素转换成为税后的值。咱们将 x -> x*x lambda表达式传到 map() 方法,后者将其应用到流中的每个元素。而后用 forEach() 将列表元素打印出来。

复制代码
// 不使用lambda表达式为每一个订单加上12%的税
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    System.out.println(price);
}
 
// 使用lambda表达式
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);
复制代码
复制代码
112.0
224.0
336.0
448.0
560.0
112.0
224.0
336.0
448.0
560.0
复制代码

6.二、Java 8中使用lambda表达式的Map和Reduce示例

Map和Reduce操做是函数式编程的核心操做,由于其功能,reduce 又被称为折叠操做。

SQL中相似 sum()、avg() 或者 count() 的汇集函数,实际上就是 reduce 操做,由于它们接收多个值并返回一个值。

流API定义的 reduceh() 函数能够接受lambda表达式,并对全部值进行合并。IntStream这样的类有相似 average()、count()、sum() 的内建方法来作 reduce 操做,也有mapToLong()、mapToDouble() 方法来作转换

复制代码
// 为每一个订单加上12%的税
// 老方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double total = 0;
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    total = total + price;
}
System.out.println("Total : " + total);
 
// 新方法:能够用内建方法,也能够本身定义
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
System.out.println("Total : " + bill);
复制代码

output:

Total : 1680.0
Total : 1680.0

七、经过过滤建立一个String列表

// 建立一个字符串列表,每一个字符串长度大于2
List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());
System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

output:

Original List : [abc, , bcd, , defg, jk], filtered list : [abc, bcd, defg]

八、对列表的每一个元素应用函数

// 将字符串换成大写并用逗号连接起来
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);

九、复制不一样的值,建立一个子列表

// 用全部不一样的数字建立一个正方形列表
List<Integer> numbers = Arrays.asList(9, 10, 3, 4, 7, 3, 4);
List<Integer> distinct = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
System.out.printf("Original List : %s,  Square Without duplicates : %s %n", numbers, distinct);

output:

Original List : [9, 10, 3, 4, 7, 3, 4],  Square Without duplicates : [81, 100, 9, 16, 49]

十、计算集合元素的最大值、最小值、总和以及平均值

ntStream、LongStream 和 DoubleStream 等流的类中,有个很是有用的方法叫作 summaryStatistics() 。能够返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描述流中元素的各类摘要数据。

最大值  最小值  全部元素的总和  平均值

复制代码
//获取数字的个数、最小值、最大值、总和以及平均值
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest prime number in List : " + stats.getMax());
System.out.println("Lowest prime number in List : " + stats.getMin());
System.out.println("Sum of all prime numbers : " + stats.getSum());
System.out.println("Average of all prime numbers : " + stats.getAverage());
复制代码

输出:

Highest prime number in List : 29
Lowest prime number in List : 2
Sum of all prime numbers : 129
Average of all prime numbers : 12.9

Lambda表达式 vs 匿名类

既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对两者作一个比较分析。

一个关键的不一样点就是关键字 this:

匿名类的 this 关键字指向匿名类,而lambda表达式的 this 关键字指向包围lambda表达式的类。

另外一个不一样点是两者的编译方式:

Java编译器将lambda表达式编译成类的私有方法。使用了Java 7的 invokedynamic 字节码指令来动态绑定这个方法

注意:

1)lambda表达式仅能放入以下代码:预约义使用了 @Functional 注释的函数式接口,自带一个抽象函数的方法,或者SAM(Single Abstract Method 单个抽象方法)类型。这些称为lambda表达式的目标类型,能够用做返回类型,或lambda目标代码的参数。例如,若一个方法接收Runnable、Comparable或者 Callable 接口,都有单个抽象方法,能够传入lambda表达式。相似的,若是一个方法接受声明于 java.util.function 包内的接口,例如 Predicate、Function、Consumer 或 Supplier,那么能够向其传lambda表达式。

2)lambda表达式内可使用方法引用,仅当该方法不修改lambda表达式提供的参数。本例中的lambda表达式能够换为方法引用,由于这仅是一个参数相同的简单方法调用。

list.forEach(n -> System.out.println(n));
list.forEach(System.out::println);  // 使用方法引用
 

然而,若对参数有任何修改,则不能使用方法引用,而需键入完整地lambda表达式,以下所示:

list.forEach((String s) -> System.out.println("*" + s + "*"));

事实上,能够省略这里的lambda参数的类型声明,编译器能够从列表的类属性推测出来。

3)lambda内部可使用静态、非静态和局部变量,这称为lambda内的变量捕获。

4)Lambda表达式在Java中又称为闭包或匿名函数,因此若是有同事把它叫闭包的时候,不用惊讶。

5)Lambda方法在编译器内部被翻译成私有方法,并派发 invokedynamic 字节码指令来进行调用。可使用JDK中的 javap 工具来反编译class文件。使用 javap -p 或 javap -c -v 命令来看一看lambda表达式生成的字节码。大体应该长这样:

private static java.lang.Object lambda$0(java.lang.String);

6)lambda表达式有个限制,那就是只能引用 final 或 final 局部变量,这就是说不能在lambda内部修改定义在域外的变量。

List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { factor++; });
Compile time error : "local variables referenced from a lambda expression must be final or effectively final"
 

另外,只是访问它而不做修改是能够的,以下所示:

List<Integer> primes = Arrays.asList(new Integer[]{2, 3,5,7});
int factor = 2;
primes.forEach(element -> { System.out.println(factor*element); })

输出:

4
6
10
14

 

分类: JDK8新特性
标签: JDK8, Java
0
0
« 上一篇: 对象在内存中初始化的过程?
» 下一篇: 第1张 Maven简介 学习笔记

Java 8 Lambda表达式和理解

说明:部分资料来源于网络

时间:20190704

Lambda 表达式,也可称为闭包,它是推进 Java 8 发布的最重要新特性。Lambda 容许把函数做为一个方法的参数(函数做为参数传递进方法中)。使用 Lambda 表达式可使代码变的更加简洁紧凑。

 

1、语法

一、lambda 表达式的语法格式以下:

  (左边)输入参数->(右边)lambda主体

(parameters) -> expression;

  或

(parameters) ->{ statements; }

 

二、如下是lambda表达式的重要特征:

(1)输入参数:

  可选类型声明:不须要声明参数类型,编译器能够统一识别参数值。

  可选的参数圆括号:

    a、一个参数无需定义圆括号,但多个参数须要定义圆括号。

    b、若是申明了参数类型,则必定须要圆括号。

(2)lambda主体

  可选的大括号:若是主体包含了一个语句,就不须要使用大括号。

  可选的返回关键字:若是主体只有一个表达式返回值则编译器会自动返回值,大括号须要指定明表达式返回了一个数值

 

三、按照上面的格式,lambda不一样参数的表达式写法

(1)没有参数的表达式:

() -> System.out.println("this is no parameter Lambda expression");

(2)只有一个参数的表达式:

(x) -> System.out.println("this is only one parameter Lambda expression");

  或者

(X x) -> System.out.println("this is only one parameter Lambda expression");

  和

(x) -> {
    x = x*2;
    System.out.println("this is only one parameter Lambda expression");
    System.out.println("the function is double input value");
    return x;
};

  说明:一个参数的能够不用使用(),若是参数声明了参数类型则必需要加()Lambda主体是语句块的话须要使用{}

(3)有两个或者多个参数的表达式:

(x,y) -> System.out.println("these are several parameters Lambda expression");

  或者

(X x,Y y) -> {
  System.out.println("the function is add two input values");
  System.out.println("these are several parameters Lambda expression");
  return x+y;
};

  说明:有多个参数的lambda表达式,参数使用,隔开。Lambda主体是语句块的话须要使用{}

 

2、Lambda 表达式实例

lambda示例1:

复制代码
/*
 * Predicate<T>接口中boolean test(T t)方法只接收一个参数,返回值为boolean类型,
 * 故lambda表达式的输入参数只有一个参数:x,lambda的主体返回值为boolean类型
 */
Predicate<Integer> atLeast5 = x -> x >= 5;
System.out.println("传入参数是否大于5:" + atLeast5.test(6));

/*
 * BinaryOperator<T>接口中R apply(T t, U u)方法接收两个泛型参数,返回值为也为泛型
 * 故lambda表达式输入Long参数有两个:x,y,lambda的主体返回值为Long类型
 */
BinaryOperator<Long> addLongs = (x, y) -> {
  Long z = x + y;
  return z;
};
System.out.println("计算传入两个Long参数的和:" + addLongs.apply(5l, 6l));

/*
 * Runnable接口中run()方法没有参数,有没有返回值,故lambda表达式没有参数,lambda主体也没有返回值
 */
Runnable run1 = () -> System.out.println("这个方法就是run里面的方法");
run1.run();

try {
  final Integer value = 9;
  /*
   *  一、Callable<V>接口中V call() throws Exception方法没有参数,故lambda表达式也不能有输入参数,
   * 返回类型为泛型,故lambda主体须要返回指定Integer类型
   *  二、由于.call()方法抛出异常,因此须要抛出或者捕获异常
   *  三、lambda表达式使用外部参数,须要是final类型,及时外部参数没有定义为final类型,
   * 也会隐式的指定为final,故值或者引用地址不能修改。
   */
  Callable<Integer> call = () -> value;
  System.out.println("无参的方法,因此lambda的参数列表中不能传递参数:" + call.call());
} catch (Exception e) {
  e.printStackTrace();
}
复制代码

lambda示例二:

复制代码
public class Java8Tester { 

  public static void main(String args[]){ 
    Java8Tester tester
= new Java8Tester();     // 类型声明     MathOperation addition = (int a, int b) -> a + b;     // 不用类型声明     MathOperation subtraction = (a, b) -> a - b;     // 大括号中的返回语句     MathOperation multiplication = (int a, int b) -> { return a * b; };     // 没有大括号及返回语句     MathOperation division = (int a, int b) -> a / b;     System.out.println("10 + 5 = " + tester.operate(10, 5, addition));     System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));     System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));     System.out.println("10 / 5 = " + tester.operate(10, 5, division));     // 不用括号     GreetingService greetService1 = message -> System.out.println("Hello " + message);     // 用括号     GreetingService greetService2 = (message) -> System.out.println("Hello " + message);     greetService1.sayMessage("Runoob");     greetService2.sayMessage("Google");   }

  // 定义接口和接口中为实现的方法   
interface MathOperation {
    int operation(int a, int b);
  }

  // 定义接口和接口中为实现的方法
  interface GreetingService {
    void sayMessage(String message);
  }

  // 定义方法,方法经过lambda表达式实现了接口中的方法   
private int operate(int a, int b, MathOperation mathOperation){     return mathOperation.operation(a, b);   } }
复制代码

执行以上代码,输出结果为:

10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Runoob
Hello Google

使用 Lambda 表达式须要注意如下两点:

Lambda表达式主要用来定义行内执行的方法类型接口,例如,一个简单方法接口。在上面例子中,咱们使用各类类型的Lambda表达式来定义MathOperation接口的方法。而后咱们定义了sayMessage的执行。

Lambda 表达式免去了使用匿名方法的麻烦,而且给予Java简单可是强大的函数化的编程能力。

Lambda表达式经常使用的场景是:函数式接口。函数式接口是指的只有一个抽象方法的接口,咱们经常使用的函数式接口有:

Runnable、Callable、PrivilegedAction、Comparator、FileFilter、PathMatcher、InvocationHandler、PropertyChangeListener、ActionListener、ChangeListener、Function、Predicate、BinaryOperator

 

3、lambda表达式中的变量做用域

lambda表达式只能引用标记了final的外层局部变量,这就是说不能在lambda内部修改定义在域外的局部变量,不然会编译错误。

Java8Tester.java 文件输入如下代码:

复制代码
public class Java8Tester {

  final static String salutation = "Hello! "; 

  public static void main(String args[]){
    GreetingService greetService1
= message -> System.out.println(salutation + message);     greetService1.sayMessage("Runoob");     //====================至关于下面==============================     GreetingService g = new GreetingService() {       @Override       public void sayMessage(String message) {         System.out.println(salutation + message);       }     };     g.sayMessage("jack");
  }   
interface GreetingService {     void sayMessage(String message);   } }
复制代码

执行以上脚本,输出结果为:

$ javac Java8Tester.java 
$ java Java8Tester
Hello! Runoob
Hello! jack

咱们也能够直接在 lambda 表达式中访问外层的局部变量:

复制代码
public class Java8Tester { 

  public static void main(String args[]) { 
    final int num = 1; 
    Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num)); 
    s.convert(2); // 输出结果为 3 
  } 

  public interface Converter<T1, T2> { 
    void convert(int i); 
  } 
}
复制代码

lambda表达式的局部变量能够不声明为final,可是不可被后面的代码修改(即隐性的具备final 的语义)

int num = 1;  
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5;  //报错信息:Local variable num defined in an enclosing scope must be final or effectively final

Lambda 表达式当中不容许声明一个与局部变量同名的参数或者局部变量。

String first = "";  
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length());  //编译会出错
相关文章
相关标签/搜索