<一> 网络编程
一.开发一个网上互相聊条的小系统
1.预备知识
1.JAVA GUI编程
2.JAVA 网络的编程
3.TCP/UDP的入门概念
4.socket的概念
如果你上述知识都没学过,也没关系,跟着做就好了,能运行就ok,理解放在学了之后。
2.具体实现一:两两配对聊天(支持多对)
服务器端程序
package web2;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ComuHost extends Application{
//输入输出流
DataOutputStream toServer = null;
DataInputStream fromServer = null;
Socket socket = null;
String s = "";
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Panel p to hold the label and text field
BorderPane paneForTextField = new BorderPane();
paneForTextField.setPadding(new Insets(5, 5, 5, 5));
paneForTextField.setStyle("-fx-border-color: green");
paneForTextField.setLeft(new Label("输入内容"));
TextField tf = new TextField();
tf.setAlignment(Pos.BOTTOM_LEFT);
paneForTextField.setCenter(tf);
BorderPane mainPane = new BorderPane();
// Text area to display contents
TextArea ta = new TextArea();
mainPane.setCenter(new ScrollPane(ta));
mainPane.setTop(paneForTextField);
// Create a scene and place it in the stage
Scene scene = new Scene(mainPane, 450, 200);
primaryStage.setTitle("Client"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
//连接服务器
try {
socket = new Socket("localhost", 8001);
fromServer = new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
}
catch (IOException ex) {
// ta.appendText(ex.toString() + '\n');
ex.printStackTrace();
}
//创建一个新的线程等待输入
new Thread(new Input(ta)).start();
//点击传输信息
tf.setOnAction(e -> {
try {
String str = tf.getText();
tf.setText("");
ta.appendText(" " + new Date() + "\n");
ta.appendText("我:" + str + "\n");
toServer.writeUTF(str);
toServer.flush();
}
catch (IOException ex) {
// System.err.println(ex);
ex.printStackTrace();
}
});
}
//创建一个输入任务等待输入
class Input implements Runnable{
TextArea ta = null;
public Input(TextArea ta) {
// TODO Auto-generated constructor stub
this.ta = ta;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
//循环监听
while(true) {
s = fromServer.readUTF();
ta.appendText(" "+new Date() + "\n");
ta.appendText("TA:" + s + "\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
launch(args);
}
}
客户端
package web2;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class ComuHost extends Application{
//输入输出流
DataOutputStream toServer = null;
DataInputStream fromServer = null;
Socket socket = null;
String s = "";
@Override // Override the start method in the Application class
public void start(Stage primaryStage) {
// Panel p to hold the label and text field
BorderPane paneForTextField = new BorderPane();
paneForTextField.setPadding(new Insets(5, 5, 5, 5));
paneForTextField.setStyle("-fx-border-color: green");
paneForTextField.setLeft(new Label("输入内容"));
TextField tf = new TextField();
tf.setAlignment(Pos.BOTTOM_LEFT);
paneForTextField.setCenter(tf);
BorderPane mainPane = new BorderPane();
// Text area to display contents
TextArea ta = new TextArea();
mainPane.setCenter(new ScrollPane(ta));
mainPane.setTop(paneForTextField);
// Create a scene and place it in the stage
Scene scene = new Scene(mainPane, 450, 200);
primaryStage.setTitle("Client"); // Set the stage title
primaryStage.setScene(scene); // Place the scene in the stage
primaryStage.show(); // Display the stage
//连接服务器
try {
socket = new Socket("localhost", 8001);
fromServer = new DataInputStream(socket.getInputStream());
toServer = new DataOutputStream(socket.getOutputStream());
}
catch (IOException ex) {
// ta.appendText(ex.toString() + '\n');
ex.printStackTrace();
}
//创建一个新的线程等待输入
new Thread(new Input(ta)).start();
//点击传输信息
tf.setOnAction(e -> {
try {
String str = tf.getText();
tf.setText("");
ta.appendText(" " + new Date() + "\n");
ta.appendText("我:" + str + "\n");
toServer.writeUTF(str);
toServer.flush();
}
catch (IOException ex) {
// System.err.println(ex);
ex.printStackTrace();
}
});
}
//创建一个输入任务等待输入
class Input implements Runnable{
TextArea ta = null;
public Input(TextArea ta) {
// TODO Auto-generated constructor stub
this.ta = ta;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
//循环监听
while(true) {
s = fromServer.readUTF();
ta.appendText(" "+new Date() + "\n");
ta.appendText("TA:" + s + "\n");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
launch(args);
}
}
思考一:如何创建一个多人的群聊?
1.每个人发送信息,群里的每个人都能收到:
开启n个线程,每个线程监听一个人的信息,服务器收到一个人的信息,传输给连接的socket数组中的每个socket。
每个线程中应该保存有所有人的socket,只能初始化完成。
2.实现群聊增加成员:
需要进程之间的通信,从主程序中将新增的socket传入每个Thread中,Thread中的socket数组就需要增加一。
3.实现通过群聊向发送信息:
socket数组中,不保存socket,而保存socket和IP的一个映射。寻找IP即可。或者保存socket,遍历数组,从数组中寻找到,socket.getIp() == IP,然后发送信息。
思考二:如何给特定人发送信息
1.正如群聊第三条,需要获取用户的IP然后发送即可
2.同时每个线程都需要所有用户的socket所以需要进行线程通信
思考三:能否用一个线程解决群聊问题
这个不会,没法处理等待读入时候的阻塞问题,就没法同时监听所有的用户的发送信息。有非阻塞的WriteUTF就可以解决这个问题。否则就只能开启线程进行监听每一个用户传输信息情况。
二.使用java发送邮件
import java.util.Properties;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
/**
* @author gyf 2018-02-27
* <p>
* SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议
* 》SMTP 服务器就是遵循 SMTP 协议的发送邮件服务器
* POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本
* 》POP3服务器则是遵循POP3协议的接收邮件服务器
*/
/*
*索要域名
*索要
* 索要发件人的账号密码
* */
public class SendJMail {
public static boolean sendMail(String email, String emailMsg) {
String from = "fuzekun255@163.com"; // 邮件发送人的邮件地址
String to = email; // 邮件接收人的邮件地址
final String username = "fuzekun255@163.com"; //发件人的邮件帐户
final String password = "fuzekun255"; //发件人的邮件密码
//定义Properties对象,设置环境信息
Properties props = System.getProperties();
//设置邮件服务器的地址
props.setProperty("mail.smtp.host", "smtp.163.com"); // 指定的smtp服务器
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.transport.protocol", "smtp");//设置发送邮件使用的协议
//创建Session对象,session对象表示整个邮件的环境信息
Session session = Session.getInstance(props);
//设置输出调试信息
session.setDebug(true);
try {
//Message的实例对象表示一封电子邮件
MimeMessage message = new MimeMessage(session);
//设置发件人的地址
message.setFrom(new InternetAddress(from));
//设置主题
message.setSubject("用户激活");
//设置邮件的文本内容
//message.setText("Welcome to JavaMail World!");
message.setContent((emailMsg), "text/html;charset=utf-8");
//设置附件
//message.setDataHandler(dh);
//从session的环境中获取发送邮件的对象
Transport transport = session.getTransport();
//连接邮件服务器
transport.connect("smtp.163.com", 25, username, password);
//设置收件人地址,并发送消息
transport.sendMessage(message, new Address[]{new InternetAddress(to)});
transport.close();
return true;
} catch (MessagingException e) {
e.printStackTrace();
return false;
}
}
}
三.使用java写一个可靠的邮箱传输协议
基本思路就是借助当前邮箱的协议,加上一个如果传输出错就报告对方,让其重新发包。
<二> 多线程的学习
一.线程有关的关键字
- synchronized(Object):排他锁,锁住对象资源
注意锁不住Integer ,String 等封装类型。
为什么?
private final int value;
这是Interger中的代码,
也就是说,一旦整数初始化完成,就不能改变了,改变了就是另一个对象了,所以锁不住。
例子如下
//测试synchronize锁不住的情况
public void testSyn() {
//输出sum的线程.输出过程中锁住sum
new Thread(() -> {
synchronized (sum) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("sum为 :" + sum);
}
}).start();
//在另一个线程中修改sum的值.
new Thread(() -> {
sum = 100;
} ).start();
}
结果为 sum = 100;也就是说synchronized没有锁住sum;
synchronized可以锁住方法
public synchronized void function()
这是实现的是互斥访问但是如果别的方法中没有加synchronized关键字,就可以访问它
例子如下
public synchronized void m1() throws InterruptedException {
b = 1000;
Thread.sleep(3000);//如果不锁住m2,那么就会被改变b
System.out.println("m1.b = " + b);
}
public int getb() {
return b;
}
public synchronized void m2() throws InterruptedException{
b = 2000;
System.out.println("m2.b = "+b);
}
- lock();
- notify
- Thread.sleep()
- ExecutorService 线程池
ExecutorService executor = Executors.newCachedThreadPool();
一.死锁问题
public class TestDeadLock implements Runnable{
public int flag = 1;
private Object o1 =new Object(),o2 = new Object();
public void run() {
System.out.println(flag);
if(flag == 1) {
synchronized (o1) {
try{
Thread.sleep(100);
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
synchronized (o2) {
System.out.println("执行完成1");
}
}
}
if(flag == 0) {
synchronized (o2) {
try {
Thread.sleep(100);
}catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
synchronized (o1) {
System.out.println("执行完成2");
}
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
TestDeadLock test = new TestDeadLock();
TestDeadLock test2 = new TestDeadLock();
test.flag=1;
test2.flag=0;
Thread thread1 = new Thread(test);
Thread thread2 = new Thread(test2);
thread1.start();
thread2.start();
}
}
二.哲学家进餐
三.读者写者问题
四.银行账户的读写锁
<三>.Java8的新特性
一.数据结构的改变
1.hash表的改进
原来的hash表就是
数组加列表
当负载大于0.75的时候就进行扩容
现在变成
数组-列表-红黑树
当一个数组的中的列表总容量大于8且数组容量大于64的时候就将列表中的元素变成红黑树。
Hash-map,Hash-set
ConcurrentHashMap:
concurrentLevel = 16
变成了CSA算法
2.内存结构 改变
二.优点
1.速度更快
2.代码更少
3.强大的Stream API
4.便于并行 parrelStream();
5.最大化减少空指针异常Optional
三.Lambda表达式
1.基本语法
(params) -> expression
(params) -> statement
(params) -> { statements }
/*
语法格式一:无参数,无返回值
()->system.out.println("hello");
语法格式二 :有一个参数,无返回值
(x)->system.out.println(x);
语法格式三:只有一个参数,小括号可以不写
x->system.out.println(x);
语法格式四:有两个参数,有返回值,有多条语句
(x,y) ->{
System.out.println("你好");
return x + y;
}
语法格式五:只有一条语句,return和大括号都可以省略不写
Comparator<Integer>com = (x, y) -> Integer.compare(x, y);
语法格式刘参数列表的数据类型可以不写,因为JVM可以通过上下文进行判断
(Integer x, Integer y) -> Integer.compare(x, y);
*/
2.使用的条件
.函数式接口
就是只能有一个方法的接口。
@fucntonalInterface进行修饰,接口只能是函数式接口
3.几个具体的实例
(1)改写死锁问题
//使用Lamta表达式写死锁问题
Object o1 = new Object(), o2 = new Object();
new Thread( () -> {
System.out.println("线程一启动....");
synchronized (o1) {
System.out.println("得到o1,等待o2");
try {
Thread.sleep(500);
} catch (Exception e) {
System.out.println("第一个sleep报错");
}
synchronized (o2) {
System.out.println("任务完成");
}
}
}).start();
new Thread( () -> {
System.out.println("线程二启动...");
synchronized(o2) {
System.out.println("得到o2,等待o1");
try {
Thread.sleep(500);
}catch(Exception e) {
System.out.println("第二个sleep报错");
}
synchronized (o1) {
System.out.println("任务2完成");
}
}
}) .start();
(2).使用Predicate接口过滤
predicate接口中有一个返回类型为bool的接口方法,只要重写这个方法就可以实现过滤作用。
public static void main(String[] args) {
String[] Language = {"Java", "Scale", "C++", "HasKel", "Lisp"};
List list = Arrays.asList(Language);
System.out.println("Language begin with J");
filter(list,(str)->((String) str).startsWith("J"));
System.out.println("Language start with a");
filter(list, (str) -> ((String) str).endsWith("a"));
System.out.println("The length of language >= 4");
filter(list, (str) -> {
int n = ((String) str).length();
if(n >= 4)return true;
else return false;
});
System.out.println("Cout All the Language");
filter(list, (str) -> true);
}
public static void filter(List<String> names, Predicate condidion) {
for(String name : names) {
if(condidion.test(name)) { //将name 传入lambda表达式进行判断
System.out.println("name :" + name);
}
}
}
(3).并行处理列表中的东西
(4).匿名内部类处理的区别
例一:
//匿名内部类
public void neibuClass() {
Comparator<Integer>com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> treeSet = new TreeSet<>(com);
}
//使用Lambda表达式
public void testLClass() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
TreeSet<Integer>ts = new TreeSet<>(com);
}
例二:
//需求:获取当前工四年龄大于32的员工信息
List<Empoyee>empoyees = Arrays.asList(
new Empoyee(14, "张三"),
new Empoyee(37, "李四"),
new Empoyee(36, "王五"),
new Empoyee(35, "赵刘")
);
public void test3() {
//获取年龄大于35
List<Empoyee>list = filterEmpoyees(empoyees);
for(Empoyee empoyee : list) {
System.out.println(empoyee);
}
//获取工资大于5000
List<Empoyee>list2 = salartfilter(empoyees);
for(Empoyee empoyee : list2) {
System.out.println(empoyee);
}
}
public List<Empoyee> filterEmpoyees(List<Empoyee> list) {
List<Empoyee>empoyees = new ArrayList<>();
for(Empoyee empoyee : empoyees) {
if(empoyee.getAge() >= 35) {
empoyees.add(empoyee);
}
}
return empoyees;
}
//需求:获取当前工人中,工资大于5000的员工信息
public List<Empoyee> salartfilter(List<Empoyee> list) {
List<Empoyee>empoyees = new ArrayList<>();
for(Empoyee empoyee : empoyees) {
if(empoyee.getSalary() >= 5000) {
empoyees.add(empoyee);
}
}
return empoyees;
}
//优化方式一:策略设局模式
public List<Empoyee> filterEmployees(List<Empoyee> list, MyPredicate<Empoyee> myPredicate) {
List<Empoyee>empoyees = new ArrayList<>();
for(Empoyee empoyee : empoyees) {
if(myPredicate.test(empoyee)) {
empoyees.add(empoyee);
}
}
return empoyees;
}
public void test4() {
List<Empoyee> list = filterEmployees(empoyees, new FilterEmployeeByAge());
for(Empoyee empoyee : list) {
System.out.println(empoyee);
}
}
//优化方式二:匿名内部类
public void test5() {
List<Empoyee> list = filterEmployees(empoyees, new MyPredicate<Empoyee>() {
@Override
public boolean test(Empoyee t) {
return t.getAge() > 16;
}
});
for(Empoyee empoyee : list) {
System.out.println(empoyee);
}
}
//优化方式三:lambda表达式
public void test6() {
List<Empoyee> list = filterEmployees(empoyees, (e) -> e.getAge() >= 16);
list.forEach(System.out::println);
List<Empoyee> list2 = filterEmployees(empoyees, (e) -> e.getSalary() >= 3500);
list.forEach(System.out::println);
}
//优化方式四:predict语法
public void test7() {
empoyees.stream()
.filter((e) -> e.getAge() >= 16)
.limit(2)
.forEach(System.out::println);
empoyees.stream()
.filter((e) -> e.getSalary() >= 3500)
.limit(3)
.forEach((x) ->{
x.setSalary(5000);
});
}
//实现两个数字的加减乘除操作
public void test8() {
System.out.println(opxy(100, 1000, (x, y)-> x + y));
}
public int opxy(int x, int y, Opration op) {
return op.oprt(x, y);
}
//调用Collection.sort()方法,通过定制排序比较两个Employee(先按住奥年龄比,年龄相同按照姓名比),使用Lambda接口作为参数传递
public void test9() {
Collections.sort(empoyees, (e1, e2) -> {
if(e1.getAge() == e2.getAge()) {
return Integer.compare(e1.getSalary(), e2.getSalary());
}else {
return Integer.compare(e1.getAge(), e2.getAge());
}
});
empoyees.forEach(System.out::println);
}
//写一个方法将接口作为参数,使得字符串被转换为大写
public void test10() {
String s = "fdafda,FDAEFA,AD";
//转换成大写
System.out.println(oprateSt(s, (x) -> x.toUpperCase()));
//转换成小写
System.out.println(oprateSt(s, (x) -> x.toLowerCase()));
//通过逗号分开
System.out.println(oprateSt(s, (x) -> x.split(",").toString()));
}
public String oprateSt(String x, StringSolve ss) {
return ss.solve(x);
}
//
public void op(long l1, long l2, MyFuction<Long, Long> mf) {
System.out.println(mf.getValue(l1, l1));
}
public void test11() {
op(55, 66, (x, y) -> x * y);
op(55, 66, (x, y) -> x + y);
}
相关类
一
public class FilterEmployeeByAge implements MyPredicate<Empoyee>{
@Override
public boolean test(Empoyee t) {
return t.getAge() >= 35;
}
}
二
public interface FilterEmployeeBySalary {
public boolean test(Empoyee e);
}
三.
@FunctionalInterface
public interface Opration{
public int oprt(int x, int y) ;
}
四.
public interface StringSolve {
public String solve(String s);
}
五
public interface MyFuction <T,R>{
public long getValue(T l1, R l2) ;
}
六
package Lamba;
public class Empoyee {
int age;
String name;
int salary;
public Empoyee(int age, String name) {
this.age = age;
this.name = name;
this.salary = (int)(Math.random() * 10000);
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSalary(int salary) {
this.salary = salary;
}
public int getSalary() {
return salary;
}
@Override
public String toString() {
return "Empoyee [age=" + age + ", name=" + name + ", salary=" + salary + "]";
}
}
(5)对一个数字进行计算
四.java8四大核心函数式接口
1.Comsumer
消费类型接口
void accept(T t)
直接消费类型
2.Supplier
供给型接口
T get();
直接获取T类型
3.function<R,T>
R apply(T);
4.Predicate
断言型接口
boolean test(T t)
传日一个t类型的数据进行测试
还有一些子类,可以传递多个参数,具体见参考文档。
代码测试
public static void main(String[] args) {
FuorFunction function = new FuorFunction();
function.test4();
}
public void test() {
getNumList(10, () -> (int)(Math.random() * 100)).forEach(System.out::println);
}
//测试Supplier函数接口
public List<Integer> getNumList(int num, Supplier<Integer> sup) {
List<Integer> list = new ArrayList<>();
for(int i = 0; i < num; i++) {
list.add(sup.get());
}
return list;
}
//测试Function接口
public void test2() {
String s = "fdad, FDADS";
strHander(s, (x) ->x.substring(0,5));
}
public void strHander(String s, Function<String, String>fun) {
System.out.println(fun.apply(s));
}
//测试Costumer接口
public void test3() {
testCuns(10000.0, (x) -> System.out.println("这次消费为:" + x + "元"));
}
public void testCuns(double money,Consumer<Double>con) {
con.accept(money);
}
//将满足条件的字符串,放入集合中
public List<String> filterStr(List<String> ss, Predicate<String>pre) {
List<String> strlist = new ArrayList<>();
for(String str : ss) {
System.out.println(str.length());
if(pre.test(str)) {
strlist.add(str);
}
}
return strlist;
}
public void test4() {
String []ss = {"中国", "必反" , "中大", "fdae"};
List<String>t = Arrays.asList(ss);
List<String>list = filterStr(t, (s) -> s.length() > 3);
for(String tmp : list) {
System.out.println(tmp);
}
}
五.方法引用
2.表达式
(1)对象::实例方法名字
(2)类::静态方法名字
(3)类::实例方法名字
3.注意事项:
(1)lambda体中的参数列表与返回类型,与函数式接口中抽象方法的函数列表和返回类型值保持一致
(2)若参数列表中第一参数是实例方法的调用者,第二参数是实例方法的参数时,可以ClassName::method;
(3)需要调用构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致。
4.示例
//类::实例方法名字
public void test4(){
BiPredicate<String, String>bp(x, y) -> x.equal(y);
//第一个参数是实例方法的调用者,第二个参数是调用方法的参数
BiPredicate<String, String>bom = String :: equal();
}
六.中间操作
1.中间操作的特点:
没有终止操作,中间操作不会执行,这就是惰性求值。
2.分类
(1)筛选与切片
常用的方法有
-
-
filter(断言型接口 Predicate)
- 根据接口函数的实现进行过滤
-
-
limit (n)
- 相当于数据库中的limit,选中前n个
-
-
skip (n)
- 相当于数据库中的skip,跳过前n个
-
-
distinct
- 去重
(2)映射
-
-
map (函数式接口 Function)
- 相当于数据库中的select name ,具体的将某一属性提取出来
-
-
flatmap(函数式接口 Function)
-
相当于集合的并集操作,将集合中的集合变得扁平。
(3)排序
-
相当于集合的并集操作,将集合中的集合变得扁平。
-
-
sorted()
- 自然排序,按照comparable 按照系统默认
- 定制排序 comparator ,自己实现的比较器排序
3.示例:
先用Employee实现Comparable接口
//使用年龄进行默认排序
@Override
public int compareTo(Object o) {
if(this.age > ((Employee)o).getAge())return 1;
else if(this.age < ((Employee) o).getAge())return -1;
else return 0;
}
public void test2(){
//需求:获取当前工四年龄大于32的员工信息
List<Employee>empoyees = Arrays.asList(
new Employee(14, "张三"),
new Employee(37, "李四"),
new Employee(36, "王五"),
new Employee(35, "赵刘")
);
//筛选与切片
//内部迭代,是sreamAPI完成的
//中间操作:不执行任何操作,也就是没有终止操作,过滤不会执行
Stream<Employee> stream = empoyees.stream()
.filter((e) -> e.getAge() > 35);
//终止操作,一次执行全部内容:这就是"惰性求值"
stream.forEach(System.out::println);
//可以短路,一旦发现n条满足的就停止。
System.out.println("大于5000的");
empoyees.stream()
.filter((e) -> e.getSalary() > 5000)
.limit(2)
.forEach(System.out::println);
//跳过和去重(重写hashcode和equals)
System.out.println("大于5000的跳过前两个");
empoyees.stream()
.filter((e) -> e.getSalary() > 5000)
.skip(2)
.distinct()
.forEach(System.out::println);
//排序
//定制排序
System.out.println("定制排序");
empoyees.stream()
.sorted((e1, e2) -> Integer.compare(e1.getSalary(), e2.getSalary()))
.forEach(System.out::println);
//自然排序
System.out.println("自然排序");
empoyees.stream()
.sorted()
.forEach(System.out::println);
}
七.终止操作
1.特点:一般是consumer接口的调用函数
比如foreach;
2.类型
(1)查找与匹配
- allMatch
- noneMatch
- anyMatch
- findFirst
- count
- max
- min
- findAny
前三个返回的boolean,后边返回Optional
如果找到的值是有可能是空的就返回Optional。
(3)归约与收集
-
-
reduce(identity(初值),accumlator(归约器))
- 将流中的所有元素反复结合起来
- map-reduce广泛应用于数据搜索
-
-
collect (Collectors.)
- Collectors方便创建常见的收集器实例包括
-
数字操作
- 最大值
- 最小值
- 求和
- 平均值 Collection.avarangeDouble(函数式接口);
- 总数字 Collectors.counting()
-
分组
- Collectors.groupingBy(函数式接口) 返回值是一个Map, map没有stream - partitioningBy
-
分区
3.注意事项
插入一个遍历map的方法
for(Map<String, String>entry : map.entrySet{
entry.getKey();
entry.getValue();
}
难一点,慢一点的
for (String key : map.keySet){
key + map.get(key);
}
4.示例
List<Employee> empoyees = Arrays.asList(
new Employee(14, "张三", Employee.Status.FREE),
new Employee(37, "李四",Employee.Status.FREE),
new Employee(36, "王五",Employee.Status.VOCATION),
new Employee(35, "赵刘",Employee.Status.BUSY)
);
boolean b1 = empoyees.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.BUSY));
System.out.println(b1);
System.out.println(empoyees.stream().anyMatch((e) -> e.getStatus().equals(Employee.Status.BUSY)));
System.out.println(empoyees.stream().noneMatch((e) -> e.getStatus().equals(Employee.Status.BUSY)));
Optional<Employee> op = empoyees.stream()
.sorted((e1,e2) -> Integer.compare(e1.getSalary(), e2.getSalary()))
.findFirst();
Optional<Employee> op2 = empoyees.stream()
.filter((e) -> e.getStatus().equals(Employee.Status.FREE))
.findAny();
Optional<Employee> op3 = empoyees.parallelStream()
.filter((e) -> e.getStatus().equals(Employee.Status.FREE))
.findAny();
System.out.println(op.get());
System.out.println(op2.get());
System.out.println(op3.get());
long count = empoyees.stream()
.filter((e) -> e.getSalary() > 5000)
.count();
System.out.println(count);
Optional<Employee> op5 = empoyees.stream()
.max((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
System.out.println(op5.get());
//使用映射提取属性
Optional<Integer> op6 = empoyees.stream()
.map(Employee::getSalary)
.min(Integer::compare);
System.out.println(op6.get());
//reduce归
Integer []nums = {1, 3, 5};
List<Integer> list = Arrays.asList(nums);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
Optional<Integer> opt1 = empoyees.stream()
.map(Employee::getSalary)
.reduce(Integer::sum);
System.out.println(opt1.get());
/*
*
* collect收集,将流转换成其他形式,接受一个Collector 接口实现,给stream芳芳
* */
List<String> list2 = empoyees.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list2.forEach(System.out::println);
Set<String> set = empoyees.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
Long count3 = empoyees.stream()
.collect(Collectors.counting());
Double ave = empoyees.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(count3);
System.out.println(ave);
Double sum2 = empoyees.stream()
.collect(Collectors.summingDouble(Employee::getSalary));
//最大值
Optional<Integer>max = empoyees.stream()
.map(Employee::getSalary)
.collect(Collectors.maxBy((e1, e2) -> Integer.compare(e1, e2)));
System.out.println(max.get());
//最小值的人
Optional<Employee>min = empoyees.stream()
.collect(Collectors.minBy((e1, e2) -> Integer.compare(e1.getSalary(), e2.getSalary())));
//怎么只收集名字和状态而不收集list
Map<Employee.Status,List<Employee>>map = empoyees.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
map.entrySet().forEach((x) -> System.out.println(x.getKey() + " :" + x.getValue()));
//多级分组
Map<Employee.Status, Map<String,List<Employee>>>mas = empoyees.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if(((Employee)e).getAge() <= 35) {
return "青年";
}else if(((Employee)e).getAge() <= 50){
return "中年";
}else {
return "老年";
}
})));
System.out.println(mas);
//分区
Map<Boolean, List<Employee>>ex = empoyees.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 8000));
System.out.println(ex);
/*
*
*
* */
Optional<Integer> count2 = empoyees.stream()
.map((e) -> 1) //每一个人返回一个1然后计算
.reduce(Integer::sum);
System.out.println(count2.get());