一、Stream流
在java8中得益于lambda所带来的函数式编程,引入了一个全新的stream流概念。
目的是简化集合和数组操作的API。
流的获取
/** --------------------Collection集合获取流------------------------------- */
Collection<String> list = new ArrayList<>();
Stream<String> s = list.stream();
/** --------------------Map集合获取流------------------------------- */
Map<String, Integer> maps = new HashMap<>();
// 键流
Stream<String> keyStream = maps.keySet().stream();
// 值流
Stream<Integer> valueStream = maps.values().stream();
// 键值对流(拿整体)
Stream<Map.Entry<String,Integer>> keyAndValueStream = maps.entrySet().stream();
/** ---------------------数组获取流------------------------------ */
String[] names = {"赵敏","小昭","灭绝","周芷若"};
Stream<String> nameStream = Arrays.stream(names);
Stream<String> nameStream2 = Stream.of(names);
流的常用方法
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
list.add("张三丰");
//过滤
list.stream().filter(f -> f.equals("张无忌")).forEach(s -> System.out.println(s));
//获取数量
long size = list.stream().filter(s -> s.startsWith("张")).count();
System.out.println(size);
//只取两个
// list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(s -> System.out.println(s));
list.stream().filter(s -> s.startsWith("张")).limit(2).forEach(System.out::println);
//跳过两个
list.stream().filter(s -> s.startsWith("张")).skip(2).forEach(System.out::println);
// map加工方法: 第一个参数原材料 -> 第二个参数是加工后的结果。
// 给集合元素的前面都加上一个:黑马的:
list.stream().map(s -> s+"的屠龙刀").forEach(a -> System.out.println(a));
// 合并流。
Stream<String> s1 = list.stream().filter(s -> s.startsWith("张"));
Stream<String> s2 = Stream.of("java1", "java2");
// public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
Stream<String> s3 = Stream.concat(s1, s2);
//去重打印
s3.distinct().forEach(s -> System.out.println(s));
求平均工资
List<Employee> one = new ArrayList<>();
one.add(new Employee("猪八戒",'男',30000d , 25000, null));
one.add(new Employee("孙悟空",'男',25000d , 1000, "顶撞上司"));
one.add(new Employee("沙僧",'男',20000d , 20000, null));
one.add(new Employee("小白龙",'男',20000d , 25000, null));
List<Employee> two = new ArrayList<>();
two.add(new Employee("武松",'男',15000d , 9000, null));
two.add(new Employee("李逵",'男',20000d , 10000, null));
two.add(new Employee("西门庆",'男',50000d , 100000, "被打"));
two.add(new Employee("潘金莲",'女',3500d , 1000, "被打"));
two.add(new Employee("武大郎",'女',20000d , 0, "下毒"));
Stream<Employee> s1 = one.stream();
Stream<Employee> s2 = two.stream();
Stream<Employee> s3 = Stream.concat(s1 , s2);
//去掉最高 最低 求平均
s3.sorted((e1,e2)->Double.compare(e1.getSalary(),e2.getSalary())).skip(1).limit(one.size()+two.size() -1).forEach(f->{
sumSalary += f.getSalary();
});
System.out.println(sumSalary/(one.size()+two.size() - 2));
//过滤完变回集合
List<Employee> list = s3.filter(f->f.getName().equals("武松")).collect(Collectors.toList());
流只能使用一次,继续s3.filter等操作将报错
二、 异常
什么是异常?
- 异常是程序在"编译"或者"执行"的过程中可能出现的问题。
- 异常是应该尽量提前避免的。
- 异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止,开发中异常是需要提前处理的。
- Java中异常继承的根类是:Throwable。
Throwable(根类,不是异常类)
/ \
Error Exception(异常,需要研究和处理)
/ \
编译时异常 RuntimeException(运行时异常)
Error : 错误的意思,严重错误Error,无法通过处理的错误,一旦出现,程序员无能为力了,
Exception:才是异常类,它才是开发中代码在编译或者执行的过程中可能出现的错误.
Exception异常的分类:
- 编译时异常:继承自Exception的异常或者其子类,编译阶段就会报错.
- 运行时异常: 继承自RuntimeException的异常或者其子类,编译阶段是不会出错的,它是在运行时阶段可能出现.
抛出异常格式:
方法 throws 异常1 , 异常2 , ..{
}
建议抛出异常的方式:代表可以抛出一切异常,
方法 throws Exception{
}
向外层抛出
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/meinv.jpg");
}
处理异常 程序不会结束运行
自己捕获异常和处理异常的格式:捕获处理
try{
// 监视可能出现异常的代码!
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常
}...
监视捕获处理异常企业级写法:
try{
// 可能出现异常的代码!
}catch (Exception e){
e.printStackTrace(); // 直接打印异常栈信息
}
Exception可以捕获处理一切异常类型!
public static void parseTime(String date) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/meinv.jpg");
} catch (Exception e) {
e.printStackTrace(); // 打印异常栈信息
}
}
三、日志
想知道一个系统运行的过程和详情可以使用日志,并可以永久存储。
之前打印日志的方式 System.out.println(); //信息只能打印到控制台,不能记录到文件,想取消记录必须改代码才行。
日志技术的优势
- 可以将系统执行的信息选择性的记录到指定的位置,控制台、文件、数据库中。
- 可以随时以开关的形式控制是否记录日志,无需修改源代码。
Logback日志框架
Logback是由log4创始人设计的另一个开源日志组件,性能比log4j要好。
Logback是基于slf4j的日志规范实现的框架。
Logback主要分为三个技术模块
- logback-core: 模块为其他两个模块奠定了基础,必须有。
- logback-classic: 它是log4j的一个改良版本,同事它实现了slf4j API。
- logback-access模块与tomcat 和 Jetty 等 Servlet容器继承,以提供HTTP访问日志功能。
官方网址: https://logback.qos.ch
- 在项目下新建lib文件夹,导入jar包。
加入到依赖库
- 新建logback.xml 在src目录下。
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--
CONSOLE :表示当前的日志信息是可以输出到控制台的。
-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!--输出流对象 默认 System.out 改为 System.err-->
<target>System.out</target>
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c [%thread] : %msg%n</pattern>
</encoder>
</appender>
<!-- File是输出的方向通向文件的 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>utf-8</charset>
</encoder>
<!--日志输出路径-->
<file>log/javase-data.log</file>
<!--指定日志文件拆分和压缩规则-->
<rollingPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!--通过指定压缩文件名称,来确定分割文件方式-->
<fileNamePattern>log/javase-data2-%d{yyyy-MMdd}.log%i.gz</fileNamePattern>
<!--文件拆分大小-->
<maxFileSize>1MB</maxFileSize>
</rollingPolicy>
</appender>
<!--
level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
, 默认debug
<root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
-->
<root level="ALL">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE" />
</root>
</configuration>
使用日志
public static final Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
logger.info("info");
logger.debug("debug");
logger.warn("warn");
logger.error("error info");
}
存储到目标文件夹中