JAVA基础知识|lambda与stream
lambda与stream是java8中比较重要两个新特性,lambda表达式采用一种简洁的语法定义代码块,允许我们将行为传递到函数中。之前我们想将行为传递到函数中,仅有的选择是使用匿名内部类,现在我们可以使用lambda表达式替代匿名内部类。在学习lambda表达式之前,建议各位看官先去学习一下匿名内部类(JAVA基础知识|内部类)。
stream提供了很多有用的api,方便了我们对集合的操作
一、lambda表达式
基本语法:
(parameters) -> expression
或
(parameters) ->{ statements; }
lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
以下是一些简单的例子,便于我们理解这些特性:
// 1. 不需要参数,返回值为5
() -> 5 // 2. 接收一个参数,()可以省略,返回其2倍的值
x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值
(x, y) ->x –y // 4. 接收2个int型整数,返回他们的和
( int x, int y) ->x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) ->System.out.print(s)
二、lambda表达式使用
2.1、在for循环中使用
package com.my.controller; import junit.framework.TestCase;
import org.junit.Test; import java.util.ArrayList;
import java.util.List; /**
* description:{description}
* author:jyy
* date:2018-01-09 16:43
* modify:{modify}
*/
public class AppTest extends TestCase { @Test
public void test() { List<String> list = new ArrayList<>();
list.add("北京");
list.add("上海");
list.add("广州");
list.add("深圳"); for (String str : list) {
System.out.println(str);
} System.out.println("================="); list.forEach(str -> System.out.println(str)); } }
执行结果:
北京
上海
广州
深圳
=================
北京
上海
广州
深圳
2.2、替代匿名内部类使用
我们使用JAVA基础知识|内部类中的try catch示例
package com.my.controller; import junit.framework.TestCase;
import org.junit.Test; import java.util.ArrayList;
import java.util.List; /**
* description:{description}
* author:jyy
* date:2018-01-09 16:43
* modify:{modify}
*/
public class AppTest extends TestCase { @Test
public void test() { //匿名内部类
new ExceptionTemplate().execute(new CatchExceptionable() {
@Override
public void catchException() {
System.out.println("代码");
}
}); //lambda表达式
new ExceptionTemplate().execute(() -> System.out.println("代码"));
} }
2.3、lambda表达式与Comparator类结合使用
package com.my.controller; import junit.framework.TestCase;
import org.junit.Test; import java.util.ArrayList;
import java.util.Comparator;
import java.util.List; /**
* description:{description}
* author:jyy
* date:2018-01-09 16:43
* modify:{modify}
*/
public class AppTest extends TestCase { @Test
public void test() { List<String> list = new ArrayList<>();
list.add("BeiJing");
list.add("ShangHai");
list.add("GuangZhou");
list.add("ShenZhen"); list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
list.forEach(str -> System.out.println(str)); System.out.println("=============="); List<String> list2 = new ArrayList<>();
list2.add("BeiJing");
list2.add("ShangHai");
list2.add("GuangZhou");
list2.add("ShenZhen"); //list2.sort((String o1,String o2) -> o1.compareTo(o2));
Comparator<String> comparator =(String o1,String o2) -> o1.compareTo(o2);
list2.sort(comparator);
list2.forEach(str -> System.out.println(str)); }
}
执行结果:
BeiJing
GuangZhou
ShangHai
ShenZhen
==============
BeiJing
GuangZhou
ShangHai
ShenZhen
2.4、 lambda不能访问非final的局部变量
之前我们说过匿名内部类不能访问非final的局部变量,其实lambda也有这个限制,lambda与匿名内部类在访问外部变量时,都不允许有修改变量的倾向。
因为实例变量存在堆中,而局部变量是在栈上分配,lambda 表达(匿名类) 会在另一个线程中执行。如果在线程中要直接访问一个局部变量,可能线程执行时该局部变量已经被销毁了,这会导致一些问题。
Java 8 的 lambda 可以捕获什么变量呢?
(1). 捕获实例或静态变量是没有限制的 (可认为是通过 final 类型的局部变量 this 来引用前两者);
(2). 捕获的局部变量必须显式的声明为 final或实际效果的final 类型。
也就是在 Java 8 下,即使局部变量未声明为 final 类型,一旦在匿名类中访问了一下就被强型加上了 final 属性,所以后面就无法再次赋值了。换句话说,如果在匿名类或 lambda 表达式中访问的局部变量,如果不是 final 类型的话,编译器自动加上 final 修饰符。
public DocApplicationTests(){
String str="123";
Consumer<String> consumer = a->System.out.print(str);
//str="345";//编译报错
}
三、流stream
Java 8 中的stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。stream API 借助于同样新出现的 lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势
生成流的两种方式:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
下面我们就来使用stream提供的各种API:
3.1、筛选和切片
方法 | 描述 |
filter | 从流中过滤元素 |
distinct | 通过流所生成的元素的hashCode()和equals()方法去重 |
limit | 截断流,选取前n个元素 |
skip | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足n个,则返回一个空流 |
package com.my.po; /**
* description:{description}
* author:jyy
* date:2018-02-11 11:06
* modify:{modify}
*/
public class Employee {
private String id;
private String name;
private double salary;
private String sex; public Employee(String id, String name, double salary,String sex) {
this.id = id;
this.name = name;
this.salary = salary;
this.sex=sex;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public double getSalary() {
return salary;
} public void setSalary(double salary) {
this.salary = salary;
} public String getSex() {
return sex;
} public void setSex(String sex) {
this.sex = sex;
} @Override
public String toString() {
return "Employee{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", salary=" + salary +
", sex='" + sex + '\'' +
'}';
} @Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return id.equals(employee.id);
} @Override
public int hashCode() {
return id.hashCode();
}
}
package com.my.controller; import com.my.po.Employee;
import junit.framework.TestCase;
import org.junit.Test; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects; /**
* description:{description}
* author:jyy
* date:2018-01-09 16:43
* modify:{modify}
*/
public class AppTest extends TestCase { @Test
public void test() {
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees); //forEach,查询所有数据
list.stream().forEach(e -> System.out.println(e.toString())); //filter,查询集合中所有的女性
list.stream().filter(e -> Objects.equals(e.getSex(), "female")).forEach(e -> System.out.println(e.toString()));
//查询集合中薪资大于6000的雇员
list.stream().filter(e -> e.getSalary() > 7000).forEach(e -> System.out.println(e)); //limit,查询前两条数据
list.stream().limit(2).forEach(e -> System.out.println(e.toString())); //distinct,去重,利用Employee对象中的hashCode()和equals()方法
list.stream().distinct().forEach(e -> System.out.println(e)); //skip,跳过前两个
list.stream().skip(2).forEach(e -> System.out.println(e)); }
}
3.2、映射
方法 | 描述 |
map(Function f) | 接受一个函数作为参数,并将函数应用到每一个元素上,返回新的元素 |
mapToDouble(ToDoubleFunction f) | 返回的新元素为double类型 |
mapToInt(ToIntFunction f) | 返回的新元素为int类型 |
mapToLong(ToLongFunction f) | 返回的新元素为long类型 |
flatMap(Function f) | 操作多层嵌套的流,使其扁平化 |
3.2.1、map
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees); //map
list.stream().map(e -> e.getSalary()).forEach(e -> System.out.println(e));
执行结果:
5000.0
7000.0
10000.0
11000.0
11000.0
可以看出,集合list经过map操作之后,类型已经改变。具体什么类型,由返回值决定
3.2.2、mapToDouble、mapToInt、mapToLong
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees); list.stream().mapToDouble(e -> e.getSalary()).forEach(e -> System.out.println(e));
执行结果:
5000.0
7000.0
10000.0
11000.0
11000.0
3.2.3、flatMap
Employee[] employees1 = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
Employee[] employees2 = {
new Employee("1005", "Marry", 5000, "male"),
new Employee("1006", "Linda", 7000, "male"),
new Employee("1007", "Cris", 10000, "female")
};
List<Employee[]> list = new ArrayList<>();
list.add(employees1);
list.add(employees2);
list.stream().flatMap(e -> Arrays.stream(e)).forEach(e -> System.out.println(e.toString()));
执行结果:
Employee{id='1001', name='李明', salary=5000.0, sex='male'}
Employee{id='1002', name='王明', salary=7000.0, sex='male'}
Employee{id='1003', name='张丽', salary=10000.0, sex='female'}
Employee{id='1004', name='谢楠', salary=11000.0, sex='female'}
Employee{id='1005', name='Marry', salary=5000.0, sex='male'}
Employee{id='1006', name='Linda', salary=7000.0, sex='male'}
Employee{id='1007', name='Cris', salary=10000.0, sex='female'}
3.3、排序
方法 | 描述 |
sorted() | 产生一个新流,其中按自然顺序排序 |
sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1005", "Marry", 6000, "male"),
new Employee("1006", "Linda", 9000, "male"),
new Employee("1007", "Cris", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees);
list.stream().map(e -> e.getSalary()).sorted().forEach(e -> System.out.println(e.toString()));
System.out.println("=======");
Comparator<String> comparator = (String o1, String o2) -> o1.compareTo(o2);
list.stream().map(e -> e.getId()).sorted(comparator).forEach(e -> System.out.println(e.toString()));
执行结果:
5000.0
6000.0
7000.0
9000.0
10000.0
10000.0
11000.0
=======
1001
1002
1003
1004
1005
1006
1007
3.4、查找与匹配
方法 | 描述 |
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
noneMatch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中的任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代——它帮你把迭代做了) |
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1005", "Marry", 6000, "male"),
new Employee("1006", "Linda", 9000, "male"),
new Employee("1007", "Cris", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees);
System.out.println("===allMatch===");
Boolean b1 = list.stream().allMatch(e -> e.getSalary() > 4000);
Boolean b2 = list.stream().allMatch(e -> e.getSalary() > 5000);
System.out.println(b1);
System.out.println(b2);
System.out.println("===anyMatch===");
Boolean b3 = list.stream().anyMatch(e -> e.getSalary() > 10000);
Boolean b4 = list.stream().anyMatch(e -> e.getSalary() > 11000);
System.out.println(b3);
System.out.println(b4);
System.out.println("===noneMatch===");
Boolean b5 = list.stream().noneMatch(e -> e.getSalary() > 10000);
Boolean b6 = list.stream().noneMatch(e -> e.getSalary() > 11000);
System.out.println(b5);
System.out.println(b6);
System.out.println("===findFirst===");
System.out.println(list.stream().findFirst().toString());
System.out.println("===findAny===");
System.out.println(list.stream().findAny().toString());
System.out.println("===count===");
System.out.println(list.stream().count());
System.out.println("===max===");
System.out.println(list.stream().max((Employee o1, Employee o2) -> {
if (o1.getSalary() > o2.getSalary()) return 1;
else return -1;
}).toString());
System.out.println("===min===");
System.out.println(list.stream().min((Employee o1, Employee o2) -> {
if (o1.getSalary() > o2.getSalary()) return 1;
else return -1;
}).toString());
执行结果:
===allMatch===
true
false
===anyMatch===
true
false
===noneMatch===
false
true
===findFirst===
Optional[Employee{id='1001', name='李明', salary=5000.0, sex='male'}]
===findAny===
Optional[Employee{id='1001', name='李明', salary=5000.0, sex='male'}]
===count===
7
===max===
Optional[Employee{id='1004', name='谢楠', salary=11000.0, sex='female'}]
===min===
Optional[Employee{id='1001', name='李明', salary=5000.0, sex='male'}]
3.5、归约
map-reduce模式,在mongoDB、spark、hadoop等都有它的身影,因google使用它进行网络搜索而出名
方法 | 描述 |
reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回T |
reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值。返回Optional<T> |
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1005", "Marry", 6000, "male"),
new Employee("1006", "Linda", 9000, "male"),
new Employee("1007", "Cris", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees);
String result1 = list.stream().map(e -> e.getName()).reduce("", (x, y) -> x + "," + y);
System.out.println(result1.substring(1));
Optional<String> result2 = list.stream().map(e -> e.getName()).reduce((x, y) -> x + "," + y);
System.out.println(result2.get());
执行结果:
李明,王明,张丽,Marry,Linda,Cris,谢楠
李明,王明,张丽,Marry,Linda,Cris,谢楠
3.6、收集
方法 | 描述 |
collect(Collector c) | 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法 |
Employee[] employees = {
new Employee("1001", "李明", 5000, "male"),
new Employee("1002", "王明", 7000, "male"),
new Employee("1003", "张丽", 10000, "female"),
new Employee("1005", "Marry", 6000, "male"),
new Employee("1006", "Linda", 9000, "male"),
new Employee("1007", "Cris", 10000, "female"),
new Employee("1004", "谢楠", 11000, "female")
};
List<Employee> list = Arrays.asList(employees);
List<String> collect = list.stream().map(e -> e.getName()).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("-------------------");
Set<String> set = list.stream()
.map(e -> e.getName())
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("-------------------");
HashSet<String> hashSet = list.stream()
.map(e -> e.getName())
.collect(Collectors.toCollection(HashSet::new));
hashSet.forEach(System.out::println);
System.out.println("-------------------");
//分组
Map<Double, List<Employee>> group = list.stream()
.collect(Collectors.groupingBy(e -> e.getSalary()));
System.out.println(group);
执行结果:
李明
王明
张丽
Marry
Linda
Cris
谢楠
-------------------
张丽
Cris
李明
王明
Linda
Marry
谢楠
-------------------
张丽
Cris
李明
王明
Linda
Marry
谢楠
{9000.0=[Employee{id='1006', name='Linda', salary=9000.0, sex='male'}], 10000.0=[Employee{id='1003', name='张丽', salary=10000.0, sex='female'}, Employee{id='1007', name='Cris', salary=10000.0, sex='female'}], 5000.0=[Employee{id='1001', name='李明', salary=5000.0, sex='male'}], 11000.0=[Employee{id='1004', name='谢楠', salary=11000.0, sex='female'}], 6000.0=[Employee{id='1005', name='Marry', salary=6000.0, sex='male'}], 7000.0=[Employee{id='1002', name='王明', salary=7000.0, sex='male'}]}
以上内容只是对lambda表达式和stream的简单介绍,在实际使用中要复杂的多
JAVA基础知识|lambda与stream的更多相关文章
- 沉淀,再出发:Java基础知识汇总
沉淀,再出发:Java基础知识汇总 一.前言 不管走得多远,基础知识是最重要的,这些知识就是建造一座座高楼大厦的基石和钢筋水泥.对于Java这门包含了编程方方面面的语言,有着太多的基础知识了,从最初的 ...
- JAVA基础知识之网络编程——-网络基础(Java的http get和post请求,多线程下载)
本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息.URL和URLConnect可以用来访问web ...
- Java基础知识总结(超级经典)
Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...
- 毕向东—Java基础知识总结(超级经典)
Java基础知识总结(超级经典) 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部分用到哪些语句,方法,和对象. 4,代码实现.用具体的java ...
- 黑马毕向东Java基础知识总结
Java基础知识总结(超级经典) 转自:百度文库 黑马毕向东JAVA基础总结笔记 侵删! 写代码: 1,明确需求.我要做什么? 2,分析思路.我要怎么做?1,2,3. 3,确定步骤.每一个思路部 ...
- JAVA基础知识|Socket
一.什么是Socket? Socket本身并不是协议,是一套完成TCP.UDP协议的调用接口(API),通过socket我们才能使用TCP/IP协议(JAVA基础知识|TCP/IP协议).Socket ...
- JAVA基础知识|TCP/IP协议
虽然写代码也有一定的年头了,但是对于一些基础概念,还是很模糊.这在后来的学习过程中,带来了很大的痛苦,所以痛定思痛,决心重新学习这些概念.并把自己的理解和查询的资料做一些整合,便于以后查阅! 一.什么 ...
- Java基础知识(壹)
写在前面的话 这篇博客,是很早之前自己的学习Java基础知识的,所记录的内容,仅仅是当时学习的一个总结随笔.现在分享出来,希望能帮助大家,如有不足的,希望大家支出. 后续会继续分享基础知识手记.希望能 ...
- java基础知识小总结【转】
java基础知识小总结 在一个独立的原始程序里,只能有一个 public 类,却可以有许多 non-public 类.此外,若是在一个 Java 程序中没有一个类是 public,那么该 Java 程 ...
随机推荐
- Java基础加强-jdk1.5的一些新特性
JDK 5.0 特性 1.静态导入(import static 语句导入一个类中的某个静态方法或所有静态方法) 如: import static java.lang.Math.*; 2.可变参数 1. ...
- YII2 实现dropDownList 联动事件
一.视图中 <div class="main-form"> <?php $form = ActiveForm::begin(); ?> <?= $fo ...
- Linux报错排解
1.Loaded plugins: product-id, search-disabled-repos, subscription-manager This system is not registe ...
- centos7安装harbor
harbor是什么? docker容器是集装箱,harbor就是放集装箱的港湾. 一.下载软件: github上选择对应版本下载 https://github.com/goharbor/harbor/ ...
- JLINK固件烧写
最近在使用uVision V5.14.0.0 的时候,由于我使用的Jlink是盗版的,导致软件总是退出,然后再网上找到了解决办法. 下面介绍解决办法: 参考: http://www.9mcu.com/ ...
- 个人作业-Alpha项目测试—luomei1547
这个作业属于哪个课程 https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/ 这个作业要求在哪里 https://edu.cnbl ...
- less避免编译
less里面有一个避免编译,有时候我们需要输出一些不正确的css语法或者使用less不认识的专有语法.要输出这样的值我们可以在字符串前加上一个~ /*避免编译*/ .test_03{ width: 3 ...
- Ubuntu系统---Ubuntu16.04进不了界面(登录界面循环,密码正确)(一体化安装(CUDA +NVIDIA驱动)+ cuDNN)
Ubuntu16.04进不了界面(登录界面循环,密码正确)(一体化安装(CUDA +NVIDIA驱动)+ cu ...
- 陈硕muduo
https://github.com/chenshuo/muduo muduo 阅读 https://www.cnblogs.com/qbits/p/11101678.html
- SmtpClient 发送邮件
利用SmtpClient 代码发送邮件. 简单测试代码: static void Main(string[] args) { MailMessage msg = new MailMessage(); ...