在思考问题时,使用不可变值和函数,函数对一个值进行处理,映射成另一个值
// 匿名内部类 button.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event){ System.out.println("button clicked"); } }); //lambda表达式 button.addActionListener(event -> System.out.println("button clicked"));
设计匿名类的目的,就是为了方便java程序员将代码作为数据传递,不过,匿名内部类还是不够简便。为了调用一行重要的逻辑代码,不得不加上多行冗余的样板代码。
在方法传入参数中,我们其实并不想传入类似对象的参数,我们更希望传入**行为,**在java8中,我们可以将内部匿名类的形式改编为lambda表达式的形式。
lambda表达式的几种变体
lambda表达式的类型依赖于上下文环境,是由编译器推断出来的,
public class LambdaExample { public static void main(String[] args) { Runnable noArguments = () -> System.out.println("hello world!"); ActionListener oneArguments = e -> System.out.println("button clicked!"); Runnable multiStatement = () -> { System.out.println("hello"); System.out.println(" World"); }; BinaryOperator3. 引用值,而不是变量add = (x, y) -> x + y; BinaryOperator addExplicit = (Long x, Long y) -> x + y; } }
匿名内部类中使用final局部变量
//匿名内部类中使用final局部变量 final String name = getUserName(); Button button = new Button(); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("hi" + name); } }); //lambda表达式中引用既成事实上的final变量 String name2 = getUserName(); //name2 = ""; //如果这么做,编译器将会报错 button.addActionListener(e -> System.out.println("hi" + name2));
java 8中虽然放松了这一限制,可以引用非final变量,但是该变量在既定事实上必须也是final的,虽然无需声明为final变量,但在lambda表达式中,也无法用作非终态变量。如果坚持用作非终态变量,编译器就会报错。
既定事实的final变量是指只能给该变量赋值一次,换句话说,lambda表达式引用的是值,而不是变量
函数接口是只有一个抽象方法的接口,用作lambda表达式的类型。
package com.ricemarch; public interface IntPred { boolean test(Integer value); }
package com.ricemarch; public class LambdaExercise { public static void main(String[] args) { //对应的lambda表达式对接口进行的实现 IntPred intPred = x -> x > 5; boolean test = intPred.test(10); System.out.println(test); } }
jdk提供了一组核心函数接口会频繁出现。
某些情况下,用户需要手动指明类型,无论哪种形式进行类型的指明,宗旨是为了代码便于阅读。
一开始类型信息是有用的,但随后的可以只在真正需要时才加上类型学习。
//使用菱形 *** 作符,根据变量类型做推断 MapoldWorldCounts = new HashMap (); Map oldWorldCounts2 = new HashMap<>();
package com.ricemarch; import java.util.Random; import java.util.function.BinaryOperator; import java.util.function.Predicate; public class LambdaInference { public static void main(String[] args) { Predicate6. 要点回顾atleast5 = x -> x > 5; int i = new Random().nextInt(); boolean test = atleast5.test(i); System.out.println(i + " " + test); BinaryOperator addLongs = (x, y) -> x + y; Long apply = addLongs.apply(1L, 1L); System.out.println(apply); } }
- lambda表达式是一种匿名方法,将行为像数据一样进行传递
- lambda表达式的常见结果:BinaryOperator addLongs = (x, y) -> x + y;
- 函数接口指仅具有单个抽象方法的接口,用来表示lambda表达式的类型
- 请看 Function 函数接口并回答下列问题。
public interface Function{ R apply(T t); }
a. 请画出该函数接口的图示。
b. 若要编写一个计算器程序,你会使用该接口表示什么样的 Lambda 表达式?
Functioncalc = t -> t * 2.0;
c. 下列哪些 Lambda 表达式有效实现了 Function
x->x+1; //OK (x,y)->x+1; //NG x->x==1;//NG
- ThreadLocal Lambda表达式。Java有一个ThreadLocal类,作为容器保存了当前线程里局部变量的值。Java 8为该类新加了一个工厂方法,接受一个Lambda表达式,并产生 一个新的 ThreadLocal 对象,而不用使用继承,语法上更加简洁。
a. 在 Javadoc 或集成开发环境(IDE)里找出该方法。
@FunctionalInterface public interface Supplier{ T get(); }
b. DateFormatter 类是非线程安全的。使用构造函数创建一个线程安全的 SimpleDateFormat对象,并输出日期,如“01-Jan-1970”。
SupplierthreadLocal = () -> ThreadLocal.withInitial(() -> new SimpleDateFormat("dd-MMM-yyyy")); SimpleDateFormat df = (SimpleDateFormat)threadLocal.get().get(); System.out.println(df.format(new Date()));
- 类型推断规则。下面是将 Lambda 表达式作为参数传递给函数的一些例子。javac 能正确推断出 Lambda 表达式中参数的类型吗?换句话说,程序能编译吗?
a. Runnable helloWorld = () -> System.out.println(“hello world”);//OK
b. 使用 Lambda 表达式实现 ActionListener 接口://OK
JButton button = new JButton(); button.addActionListener(event -> System.out.println(event.getActionCommand()));
c. 以如下方式重载 check 方法后,还能正确推断出 check(x -> x > 5) 的类型吗?
不能正确推导,有歧义,因为输入的值都是Integer,返回都是boolean
No - the lambda expression could be inferred as IntPred or Predicate so the overload is ambiguous.
interface IntPred { boolean test(Integer value); } boolean check(Predicatepredicate); boolean check(IntPred predicate);
写成如下形式就可以推导类型:
public interface IntPred { boolean test(Double value); public boolean check(IntPred intPred, Double i){ return intPred.test(i); } public boolean check(Predicatepredicate,Integer i){ return predicate.test(i); } //执行 System.out.println(check(x -> x > 5, 6.0)); System.out.println(check(x -> x > 10, 6)); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)