

在java的历史中,java8的变化举重若轻
1、让方法参数具备行为能力
1.1、找绿色的苹果
其中apple类是一个实体类它有颜色、重量等属性
上面的例子是遍历参数中的apple集合找到颜色为绿色的苹果
用下面的这个方法创建出需要的apple集合
List<Apple> list = Arrays.asList(new Apple("green", 150), new Apple("yellow", 120), new Apple("green", 170));
1.2、找红色的苹果
最初级的办法就是另外再写一个方法。
高级一点的就是在上面方法上加一个参数为我们需要找的颜色
1.3、根据颜色又根据重量去查找
1.3.1、策略模式的应用,方法参数具备了行为
这种仓促的变化代表着需求的不断变化,对于我们写程序的来说如何让调用者察觉不到这种变化?
public class FilterApple {
定义一个接口作为作为方法的参数,具体的业务算法作为他的实现类
public interface AppleFilter {
boolean filter(Apple apple);
}
public static List<Apple> findApple(List<Apple> apples, AppleFilter appleFilter) {
List<Apple> list = new ArrayList<>();
for (Apple apple : apples) {
if (appleFilter.filter(apple))
list.add(apple);
}
return list;
}
实现我们定义的接口,写我们的业务逻辑
public static class GreenAnd160WeightFilter implements AppleFilter {
@Override
public boolean filter(Apple apple) {
return (apple.getColor().equals("green") && apple.getWeight() >= 160);
}
}
public static void main(String[] args) throws InterruptedException {
List<Apple> list = Arrays.asList(new Apple("green", 150), new Apple("yellow", 120), new Apple("green", 170));
List<Apple> result = findApple(list, new GreenAnd160WeightFilter());
System.out.println(result);、
}
}
1.3.2、直接使用匿名内部类来调用
对于上一节的策略模式,如果我们每一个业务逻辑都要写一个filter来实现这个业务的具体算法,是很麻烦的
List<Apple> yellowList = findApple(list, new AppleFilter() {
@Override
public boolean filter(Apple apple) {
return "yellow".equals(apple.getColor());
}
});
System.out.println(yellowList);
2、使用lamda表达式改写
2.1、优点:相比较上面的例子
- 一个是代码量比较大
- 另一个是this的混淆(这个理由有点牵强)
如下在这个匿名类中输出的是多少
当然是5了 - 最重要的是java8内存的变化
可以看出jdk8比jdk6少了一个P,多了M、CCS
具体后面再说
2.2、详细使用
当一个接口中有且只有一个抽象方法我们就可以使用lamda表达式(default、static方法除外)
接口上可以标上注解@FunctionalInterface(也可以不写这个注解,它起到标识验证的作用)
@FunctionalInterface
public interface AppleFilter {
boolean filter(Apple apple);
}
还可以继续简写
参数类型可以推导,所以不用写参数类型
如果只有一个参数,可以去掉参数两边的括号
2.3、其他例子
线程的对比
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}).start();
new Thread(() -> System.out.println(Thread.currentThread().getName()) ).start();
Thread.currentThread().join();
以及
这些接口
3、lambda表达式语法
方法引用、类型推导、组合
他可以被定义、有传递参数、可以有返回值、可以抛出一系列异常
3.1、参数传递
红色语句两边没有加花括号,它的返回类型可以自动推导
如果加了花括号就必须写return
3.2、被定义(function接口)
lambda是一个最基本的东西,它主要是为我们 的function接口来服务的
Function<String,Integer> flambda = s->s.length();
Integer hello = flambda.apply("hello");
System.out.println(hello);//5
Function源码
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
/**
* Returns a composed function that first applies the {@code before}
* function to its input, and then applies this function to the result.
* If evaluation of either function throws an exception, it is relayed to
* the caller of the composed function.
*
* @param <V> the type of input to the {@code before} function, and to the
* composed function
* @param before the function to apply before this function is applied
* @return a composed function that first applies the {@code before}
* function and then applies this function
* @throws NullPointerException if before is null
*
* @see #andThen(Function)
*/
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
Function 接口中还有default static方法
3.3、Predicate接口
可以看出,它是给一个参数返回一个boolean值
源码
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
使用
Predicate<String> b = s->s.length()>2;
System.out.println(b.test("hello")); //true
System.out.println(b.test("h")); //false
3.4、其他合法的lambda表达式及语法总结
4、Lambda使用深入解析
Runnable r1 = () -> System.out.println("Hello");
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
process(r1);
process(r2);
process(() -> System.out.println("Hello"));*/
这三个打印完全一致
4.1、Predicate<`T>
private static List<Apple> filter(List<Apple> source, Predicate<Apple> predicate) {
List<Apple> result = new ArrayList<>();
for (Apple a : source) {
if (predicate.test(a))
result.add(a);
}
return result;
}
List<Apple> list = Arrays.asList(new Apple("green", 120), new Apple("red", 150));
List<Apple> greenList = filter(list, (apple) -> apple.getColor().equals("green"));
System.out.println(greenList);
可以接受两个参数
只接受一个int参数
4.2、Consumer<`T>
private static void simpleTestConsumer(List<Apple> source, Consumer<Apple> consumer) {
for (Apple a : source) {
consumer.accept(a);
}
}
simpleTestConsumer(list, a -> System.out.println(a));
两个参数
BiConsumer<String,Integer> bc = (s,i)-> System.out.println(s.concat(i.toString()));
bc.accept("hello",3000);//hello3000
4.3、Function<T,
R>
private static String testFunction(Apple apple, Function<Apple, String> fun) {
return fun.apply(apple);
}
String result3 = testFunction(new Apple("yellow", 100), (a) -> a.toString());
System.out.println(result3);
BiFunction<T, U, R>
IntFunction
4.4、Supplier<`T>
Supplier<String> s = String::new; //method inference.
System.out.println(s.get().getClass());
private static Apple createApple(Supplier<Apple> supplier) {
return supplier.get();
}
Apple a2 = createApple(() -> new Apple("Green", 100));
System.out.println(a2);
4.5、Runnable
lambda表达式实际也是一个匿名函数,和内部类一样,
如果在匿名函数里操作外面的变量,则这个变量必须是final
如果仅仅是引用则不需要
5、Lambda方法推导详细解析
//这个方法是将一个字符串输出两遍
private static <T> void useConsumer(Consumer<T> consumer, T t) {
consumer.accept(t);
consumer.accept(t);
}
public static void main(String[] args) {
Consumer<String> consumer = (s) -> System.out.println(s);
useConsumer(consumer, "Hello Alex");
}
上面是正常方法调用
下面说方法推导
可以省略Consumer的定义
useConsumer(s -> System.out.println(s), "Hello Alex");
useConsumer(System.out::println, "Hello Wangwenjun");
再看 list.sort的方法推导
List<Apple> list = Arrays.asList(new Apple("abc", 123), new Apple("Green", 110), new Apple("red", 123));
System.out.println(list);
list.sort((a1, a2) -> {return a1.getColor().compareTo(a2.getColor());};
list.sort((a1, a2) -> a1.getColor().compareTo(a2.getColor()));
System.out.println(list);
list.stream().forEach的函数推导
list.stream().forEach(a -> System.out.println(a));
System.out.println("==========================");
list.stream().forEach(System.out::println); //推导之后更加简洁
什么情况下可以进行方法推导(函数推导)呢
下面分小节细说
5.1、可以通过类的静态方法推断 ::
int value = Integer.parseInt("123");
Function<String, Integer> f = Integer::parseInt;//方法推导
Integer result = f.apply("123");
System.out.println(result);
5.2、实例方法推断 ::
String s = new String("hello");
char c1 = s.charAt(2);
BiFunction<String, Integer, Character> f2 = String::charAt;
Character c = f2.apply("hello", 2);
System.out.println(c);
5.3、已有对象的实例方法 ::
String str = new String("Hello");
Function<Integer, Character> f3 = str::charAt;
Character c2 = f3.apply(4);
System.out.println(c2);
可以看看与实力方法的区别
5.4、构造函数的推导::
一个参数
Supplier<String> supplier = String::new;
String s = supplier.get();
System.out.println(s);
两个参数
BiFunction<String, Long, Apple> appleFuntion = Apple::new;
Apple apple = appleFuntion.apply("red", 100L);
System.out.println(apple);
三个参数(自己构造)
@FunctionalInterface
public interface ThreeFunction<T, U, K, R> {
R apply(T t, U u, K k);
}
ThreeFunction<String, Long, String, ComplexApple> threeFunction = ComplexApple::new;
ComplexApple complexApple = threeFunction.apply("Green", 123L, "FuShi");
System.out.println(complexApple);
5.5、list.sort优化
优化
List<Apple> list2 = Arrays.asList(new Apple("abc", 123), new Apple("Green", 110), new Apple("red", 123));
System.out.println(list2);
list2.sort(Comparator.comparing(Apple::getColor));//方法推导
System.out.println(list2);
推导过程
将前面的sort与这个进行对比发现简洁了很多
看它源码
java.util.List#sort 方法源码
@SuppressWarnings({"unchecked", "rawtypes"})
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
再看java.util.Comparator.comparing源码
public static <T, U> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor,
Comparator<? super U> keyComparator)
{
Objects.requireNonNull(keyExtractor);
Objects.requireNonNull(keyComparator);
return (Comparator<T> & Serializable)
(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
keyExtractor.apply(c2));
}
它返回值中使用了一个 & 这个有什么用
对比
list.sort((a1, a2) -> a1.getColor().compareTo(a2.getColor()));
(c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2));
而
Function<T, R> keyExtractor.apply(c1)
返回 Function 接口