欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

Java8 (1)

发布时间:2023/12/4 67 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Java8 (1) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

参考资料:

  《Java8 in Action》 Raoul-Gabriel Urma

一、jdk8

  客观的说,Java8是一次有重大演进的版本,甚至很多人认为java8所做的改变,在许多方面都比Java历史上任何一次改变都深远。

    Scala,python这样优秀编程语言中对函数式编程的处理,guava中的理念等等....

  java8的代码更简洁...

  java8对并发编程更加友好,java一直努力让并发编程更为高效,出错更少,jdk1.0里有线程和锁,Java 5增加的工业模块,Thread pools和一大堆并发工具类, Java7增加了fork/join框架,Java8则对并行提供了一个新的思路

  新的API,例如Stream等  

  等等

二、通过行为参数化传递代码

首先有一个苹果类

public static class Apple {private int weight = 0;private String color = "";public Apple(int weight, String color){this.weight = weight;this.color = color;}public Integer getWeight() {return weight;}public void setWeight(Integer weight) {this.weight = weight;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}public String toString() {return "Apple{" +"color='" + color + '\'' +", weight=" + weight +'}';}}

 

1. 需求

  需要2个函数以供过滤出需要的苹果

public static List<Apple> filterApplesByColor(List<Apple> inventory, String color){List<Apple> result = new ArrayList<Apple>();for(Apple apple: inventory){if(apple.getColor().equals(color)){result.add(apple);}}return result;}public static List<Apple> filterApplesByWeight(List<Apple> inventory, int weight){List<Apple> result = new ArrayList<Apple>();for(Apple apple: inventory){if(apple.getWeight() > weight){result.add(apple);}}return result;}

上面的代码比较啰嗦,而且如果还有新的需求,依旧需要添加新的方法,以前的java实现函数就是静态方法。

2. 第一次改造

Java中封装行为的方式只能通过匿名类之类的方式。首先定义一个接口:

interface ApplePredicate{public boolean test(Apple a);}

于是方法变为:

public static List<Apple> filter(List<Apple> inventory, ApplePredicate p){List<Apple> result = new ArrayList<Apple>();for(Apple apple : inventory){if(p.test(apple)){result.add(apple);}}return result;}

在之前的java,用如下方式:

static class AppleWeightPredicate implements ApplePredicate{public boolean test(Apple apple){return apple.getWeight() > 150;}}static class AppleColorPredicate implements ApplePredicate{public boolean test(Apple apple){return "green".equals(apple.getColor());}}

2个新的实现类,从设计模式上是策略模式... 可以更灵活的扩展,但是感觉代码更啰嗦了...

当然你也可以不定义出类,使用匿名内部类,还是很啰嗦.

List<Apple> redApples2 = filter(inventory, new ApplePredicate() {public boolean test(Apple a){return a.getColor().equals("red");}});

 

3. 使用Lambda表达式

List<Apple> result = filter(inventory ,(Apple apple)-> "red".equals(apple.getColor()));

jdk8中再进一步将Perdicate抽象为泛型类...

public interface Predicate<T> {boolean test(T var1);//.... }

三、Lambda表达式

3.1 lambda简介

很多语言都支持lambda,例如python,可以把lambda表达式简单理解为表示可传递的匿名函数的一种方式: 它没有名称,但是有参数列表、函数主题、返回类型,可能还有一个异常列表.

  • 匿名 - 没有方法名
  • 函数 - Lambda不属于任何一个类。
  • 传递 - 可以做为参数传递给方法或者存储在变量中
  • 简洁

让我们来改造一段代码...

Comparator<Apple> byWeight = new Comparator<Apple>() {@Overridepublic int compare(Apple o1, Apple o2) {return o1.getWeight().compareTo(o2.getWeight());}};Comparator<Apple> byWeight2 = (Apple a1, Apple a2) -> a1.getWeight() - a2.getWeight();

(Apple a1, Apple a2) 是Lambda的参数列表,加上一个小箭头,加上主体 a1.getWeight() - a2.getWeight()

 

Lambda的基本语法:

  (params) -> experssion

  (params) -> {statements;}

举例:

 (1) () -> {};

 (2) () -> "Raoul"

 (3) () -> {return "aaa";}

 (4) (int i) -> return "Al" + 1;

 (5) (String s) -> {"IronMan";}

上述中只有(4), (5) 不符合语法,(4)的主体是statements;需要用{},(5)的主体是statements,因此不能使用{}...

 

3.2 在哪里可以使用Lambda

1. 函数式接口

  函数是接口就是只定义了一个抽象方法的接口。 jdk8中接口还可以定义默认方法,哪怕有很多的默认方法,但是只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。

  Lambda允许你把lambda表达式作为函数式接口的一个实现的实例

  

MyInteface myInteface = (int i, int j) -> i+j;System.out.println(myInteface.add(1,2));public interface MyInteface{int add(int i, int j);}

 

2. 函数式描述符

 函数式接口中有且只有一个方法,这个方法的签名就是lambda表达式的签名。这种抽象方法叫做函数描述符...

@FuntionalInterface?

  接口标注,表示接口会被设计为一个函数式接口。按照官方说法就是:  

  • The type is an interface type and not an annotation type, enum, or class.
  • The annotated type satisfies the requirements of a functional interface.

 

3.3 使用函数式接口

java.util.function包中引入了常用的函数式接口

1. Predicate

public static <T> List<T> filte(List<T> list, Predicate<T> p){List<T> results = new ArrayList<T>();for (T t : list) {if (p.test(t)) results.add(t);}return results;}

Predicate中还有一些add, not等默认方法,暂不讨论...

2. Consumer

其中定义了一个accept()方法,没有返回值

public static <T> void forEach(List<T> list, Consumer<T> c){for (T i : list) {c.accept(i);}}public static void main(String[] args) {forEach(Arrays.asList(1,2,3,4,5),(Integer i) -> {System.out.println(i);});}

 

3. Function

类似于Guava的Function,定义了一个apply的方法,例子中打印每个字符串的长度...

public static <T, R> List<R> map(List<T> list, Function<T, R> f){List<R> result = new ArrayList<R>();for (T t : list) {result.add(f.apply(t));}return result;}public static void main(String[] args) {List<Integer> l = map(Arrays.asList("lambdas","in","action"),(String s) -> s.length());System.out.println(l);}

 

4. IntPredicate

自从jdk1.5之后就支持自动装箱inbox,但装箱之后比如将一个原始类型转换成了Integer,在heap划分一块内存分配等等,IntPredicate可以避免无谓的装箱..

IntPredicate evenNumbers = (int i) -> i%2 ==1;Predicate<Integer> predicate = (Integer i) -> i%2 ==1;

也可以说因为泛型往往不能使用基本类型

 

3.4 方法引用

方法引用可以被看做仅仅调用特定Lambda的一种快捷写法。例如

(Apple a) -> a.getWeight() 可以写成 Apple::getWeight

() -> Thread.currentThread.dumpStack() 可以写成 Thread.currentThread()::dumpStack

(str, i) -> str.substring(i) 可以写成 String:substring

(Sring s) -> System.out.println(s) 可以写成 System.out::println

 

如何构建方法引用?

(1) 静态方法,类的方法,例如Interger的parseInt Interger::parseInt

(2) 实例方法, String::length

(3) 指向现有方法的方法引用: expensiveTransaction::getValue

实例: 排序

使用Lambda表达式的用法

public static void main(String[] args) {Comparator<String> comparator = (String s1,String s2) -> s1.compareToIgnoreCase(s2);List<String> l = Arrays.asList("a","b","A","B");Collections.sort(l,comparator);System.out.println(l);}

可换成:

Comparator<String> comparator = String::compareToIgnoreCase;List<String> l = Arrays.asList("a","b","A","B");Collections.sort(l,comparator);System.out.println(l);

构造函数引用...

 

3.5 Lambda表达式复合用法

1. 比较器复合

public static void main(String ... args){List<Apple> inventory = new ArrayList<>();inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")));//1. 使用逆序 inventory.sort(Comparator.comparing(Apple::getWeight).reversed());//2. 比较器链 inventory.sort(Comparator.comparing(Apple::getWeight).reversed().thenComparing(Apple::getColor));}

比较器链中如果重量相同,就按颜色排序...

 

2. 谓词复合

public static void main(String ... args){Predicate<Apple> redApple = (Apple a) -> "red".equals(a.getColor());Predicate<Apple> notRedApple = redApple.negate();Predicate<Apple> redAndHeavyApple = redApple.and(a -> a.getWeight()>150);Predicate<Apple> readAndHeavyOrGreenApple = redApple.and(a -> a.getWeight()>150).or(a -> "green".equals(a.getColor()));}

 

3. 函数复合

 以Function为例,实现类似于g(f(x))和f(g(x))的效果

public static void main(String... args) {Function<Integer, Integer> f = x -> x + 1;Function<Integer, Integer> g = x -> x * 2;Function<Integer, Integer> h = f.andThen(g);Function<Integer, Integer> k = f.compose(g);System.out.println(h.apply(3));System.out.println(k.apply(3));}

 

转载于:https://www.cnblogs.com/carl10086/p/6035731.html

总结

以上是生活随笔为你收集整理的Java8 (1)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。