java1.8lambda表达式总结

一、基础

基本语法

[接口声明] = (参数)-> {代码。。。};

具体使用

1.表达式必须和接口绑定使用,符合接口的方法声明。
如某个接口:

public interface A {
    String get(int i);
}

声明接口时:

A a  = new A() {
    @Override
    public String get(int i) {
        return "hello " + i;
    }
};

使用lambda

A la = (int i) -> {
    return "lambda " + i;
};

但如果一个接口有多个方法,则无法使用lambda表达式。如

public interface B {
    String get(int i);
    void set();
}

default和static方法除外

public interface A {
    String get(int i);

    default int fun1() {
        return 0;
    }

    static String fun2() {
        return "A";
    }
}

2.参数:可以是0到n个参数,具体根据绑定的接口而定,且参数类型可以不写。

A la = (i) -> {
    return "lambda " + i;
};

3.返回值:如果代码块只有一行,可以没有大括号。
没有大括号时,不能用return关键字。
如果添加了大括号,或者有多行代码,必须通过关键字return返回。

//可以这样
A la2 = (i) -> "lambda " + i;
//也可以这样
A la2 = (i) -> {
    return "lambda " + i;
};
//而不能这样
A la2 = (i) -> return "lambda " + i;

java.util.function提供了大量的函数式接口供我们使用

Predicate,传入T类型,返回boolean
Consumer,传入T类型,消耗掉,返回void
function,传入T类型,返回E类型
Supplier,传入返回T类型
UnaryOperator,传入T,返回T
BinaryOperator,传入两个T类型,返回T类型
emmm,记不住~~~

如Predicate
 Predicate<String> pre1 = (name) -> "admin".equals(name);
 System.out.println(pre1.test("admin") ? "管理员" : "普通用户");

 打印结果:
 管理员

lambda对this关键字的优化

使用lambda表达式时,在表达式内部this代表的是该lambda表达式所属的对象。
正常情况下,在接口内部使用this,该this指的是这个接口,而不是声明该接口的对象(或者说该接口所属的对象)

public class Test{
    String s1 = "全局变量";
    public void testLambda() {
        String s2 = "局部变量";
        new Thread(new Runnable() {
            @Override
            public void run() {
                String s3 = "内部变量";
                System.out.println(this.s1);//报错!!!
                System.out.println(s2);
                System.out.println(s3);
            }
        }).start();
    }

    public static void main(String[] args) {
        new App().testLambda();
    }
}
public class Test {
    String s1 = "全局变量";
    public void testLambda() {
        String s2 = "局部变量";
        new Thread(() -> {
            String s3 = "内部变量";
            System.out.println(this.s1);//不报错!!!
            System.out.println(s2);
            System.out.println(s3);

        }).start();
    }

    public static void main(String[] args) {
        new App().testLambda();
    }
}

打印结果:
全局变量
局部变量
内部变量

方法重载对lambda表达式的影响

当遇到重载方法时,如果方法中传入的接口中的方法参数类型和返回值一样,则无法使用lambda。如

public class Test {

    public static void main(String[] args) {
        test(() ->{//报错!!!
            System.out.println("I1");
            return 1;
        });
    }
    //重载方法
    private static void test(A a) {
        a.printString();
    }
    private static void test(B b) {
        b.printInt();
    }

}

interface A {
    void printString();
}
interface B {
    void printInt();
}

二、lambda在集合中的应用

方法引用

1. 静态方法、实例方法引用

以List.sort() 为例
实体类:

class Person {
    private String name;
    private int age;

    public static int compareByAge(Person p1, Person p2) {
        return p1.age - p2.age;
    }

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    setter and getter...

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
数据源
        List<Person> persons = new ArrayList<>();
        persons.add(new Person("Tom", 28));
        persons.add(new Person("Jack", 30));
        persons.add(new Person("Dav", 20));
使用内部类方式
        //使用内部类方式
        persons.sort(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                int i = o1.getAge() - o2.getAge();
                return i;
            }
        });
使用lambda方式
        //使用lambda方式
        persons.sort((a, b) -> a.getAge() - b.getAge());
        persons.sort(Comparator.comparingInt(Person::getAge));
先在任意一个类中定义参数为(Person p1, Person p2),返回类型为 int 的静态方法和普通方法
class PersonUtil {
    public int compareByAge(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }

    public static int compare(Person p1, Person p2) {
        return p1.getAge() - p2.getAge();
    }
}
静态方法引用,类名::静态方法名
//静态方法的引用,会默认将(Person, Person)参数传递给PersonUtil的compare方法
persons.sort(PersonUtil::compare);
实例方法引用,对象::普通方法名
//实例方法的引用
PersonUtil pu = new PersonUtil();
persons.sort(pu::compareByAge);
2. 构造方法引用

除了静态方法引用和实例方法引用还有构造方法引用。

interface IPerson {
    //通过指定类型的构造方法初始化对象数据,
    //即:Person类中必须有(String name, int age)类型参数的构造方法。
    Person initPerson(String name, int age);
}

//构造方法的引用
IPerson ip = Person::new;
Person wang = ip.initPerson("wang", 25);

Stream

Stream解耦了对数据的各种操作,比起传统的手动操作数据更方便。
例如:

List<String> list = new ArrayList<>();
list.add("abc");
list.add("adcd");
list.add("adcde");
list.add("adcdef");
//传统方式获取list中元素长度>=4的数据
List<String> result = new ArrayList<>();
for (String s : list) {
    if (s.length() >= 4) {
        result.add(s);
    }
}
System.out.println(result);
//使用Stream方式获取list中元素长度>=4的数据
List<String> collect = list.stream().filter(s -> s.length() >= 4).collect(Collectors.toList());
System.out.println(collect);

打印结果:
[adcd, adcde, adcdef]
[adcd, adcde, adcdef]
Stream概述
/**
 * 1. 获取Stream对象
 *      1.  从集合或数组中获取[**]
 *          Collection.stream(),如list.stream()
 *          Collection.parallelStream()
 *          Arrays.stream()
 *      2.  BufferReader
 *          BufferReader.lines()
 *      3.  静态方法
 *          java.util.stream.IntStream.range()..
 *          java.nio.file.Files.walk()..
 *      4.  自定义构建
 *          java.util.Spliterator
 *      5.  更多方式。。
 *          Random.ints()
 *          Pattern.splitAsStream()..
 * 2. 中间操作api
 *      操作结果是一个Stream,中间操作可以有一个或多个连续的中间操作,需要注意的是,中间操作只记录操作方式,
 *      不做具体执行,直到借宿操作发生时,才做数据的最终执行。
 *      中间操作:就是业务逻辑处理。
 *      中间操作过程:
 *              无状态:数据处理是,不搜前置中间操作的影响。
 *                      map/filter/peek/parallel/sequential/unordered
 *              有状态:数据处理时,受前置中间操作的影响。
 *                      distinct/sorted/limit/skip
 * 3. 终结操作 | 结束操作{Terminal}
 * 需要注意:一个Stream对象,只能由一个Terminal操作,这个操作一旦发生,就会真实的处理数据。
 * 终结操作:
 *          非短路操作:当前的Stream对象必须处理完集合中所有数据才能得到结果。
 *                      forEach/forEachOrdered/toArray/reduce/collect/min/max/count/iterator
 *          短路操作:当前的Stream对象在处理过程中,一旦满足某个条件,就可以得到结果。
 *                      anyMatch/allMatch/noneMatch/findFirst/findAnd等
 */

对比上面例子

list.stream()  //获取Stream
.filter(s -> s.length() >= 4)  //中间操作,返回一个Stream对象
.collect(Collectors.toList());  //终结操作

Stream的获取

//多个数据
Stream<String> stream1 = Stream.of("A", "B", "C");

//数组
String[] strArray = new String[]{"A", "B", "C"};
Stream<String> stream2 = Stream.of(strArray);

//列表
ArrayList<Object> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Stream<Object> stream3= list.stream();

//集合
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");
Stream<String> stream4 = set.stream();

//map
HashMap<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
Stream<Map.Entry<String, Integer>> stream5 = map.entrySet().stream();

Stream对象对于基本数据类型的封装

// int / long / double
IntStream.of(new int[] {10, 20, 30}).forEach(System.out::println);
IntStream.range(1,5).forEach(System.out::println);
IntStream.rangeClosed(1,5).forEach(System.out::println);

从Stream中获取指定的类型数据

Stream<String> stream1 = Stream.of("A", "B", "C");
//array
String[] arrayx = stream1.toArray(String[]::new);
//string
String stringx = stream1.collect(Collectors.joining());
//list
List<String> listx = stream1.collect(Collectors.toList());
//set
Set<String> setx = stream1.collect(Collectors.toSet());
//map
Map<String, String> mapx = stream1.collect(Collectors.toMap(x -> "key:" + x, y -> "val:" + y));
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,548评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,497评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,990评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,618评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,618评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,246评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,819评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,725评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,268评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,356评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,488评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,181评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,862评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,331评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,445评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,897评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,500评论 2 359