Java小笔记

java每日小笔记

遍历

forEach

1
2
3
for (File f : files) {
System.out.println(f);
}

foreach相对于for循环,代码减少了,但是foreach依赖IEnumerable(IEnumerable是一个接口,它定义一个方法GetEnumerator,它返回一个IEnumerator接口,这允许只读访问一个集合,然后实现IEnumerable的集合可以与for-each语句一起使用)。
在运行的时候效率低于for循环。当然了,在处理不确定循环次数的循环,或者循环次数需要计算的情况下,使用foreach比较方便。而且foreach的代码经过编译系统的代码优化后,和for循环的循环类似。

  • 如果只是遍历集合或者数组,用foreach好些,快些。
  • 如果对集合中的值进行修改,确定循环次数就要用for循环了。

    日期转换

    SimpleDateFormate简单用法

    Date类型转化成为String
    ①.
    1
    2
    3
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String date=sdf.formate(date);(字符串时间格式不同)
    ②.
    1
    SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日  HH时mm分ss秒");
    注意:用Mybatis往Mysql中添加时间时候,mysql 类型datetime ,往里面存是 时间对象可以是String和java.sql.Timestamp 两种类型,String类型的时间必须是“yyyyu-MM-dd HH:mm:ss”格式
    String 类型转化成Date
    1
    2
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
    Date start = sdf.parse(startTime);
    注意:传递进来的startTime是String类型的字符串,其格式必须和SimpleDateFormate里面的参数形式一直,不能任何格式的字符串都可以转化,要不出现转发异常

    代码优化

    空间复杂度:以时间换空间

  • 对一个算法在运行过程中临时占用存储空间大小的量度*
    目的:找出roles集合中是否有与userInfo中id相同的,如果有就setChecked(true),即被选中
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    List<Role> roles = roleService.find(null);
    UserInfo userInfo = userInfoService.findByI(id);

    Map<Integer,Role> roleMap = new HashMap<>();
    for(Role role : roles) {
    roleMap.put(role.getId(), role);
    }
    for(Role r : userInfo.getRoles()) {
    if(roleMap.containsKey(r.getId())) {
    roleMap.get(r.getId()).setChecked(true);
    }
    }

    时间复杂度:以空间换时间

    1
    2
    3
    4
    5
    6
    7
    8
    List<Role> roles = roleService.find(null);
    UserInfo userInfo = userInfoService.findByI(id);

    for(Role role : roles) {
    for(Role r : userInfo.getRoles()) {
    role.setChecked(role.getId() == r.getId());
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //时间复杂度为:O(n²)
    public void fun() {
    int n = 100;//执行次数:1
    int sum = 0;//执行次数:1
    for (int i = 1; i <= n; ++i) {//执行次数:n
    for (int j = 1; j <= n; ++j) {//执行次数:n*n
    sum += j;//执行次数:n*n
    }
    }
    }

    请求转发和重定向的区别和应用场景

    请求转发

  • 一次请求,两次转发*
    request.getRequestDispatcher(URL地址).forward(request, response)
    处理流程:

    1.客户端发送请求,Servlet做出业务逻辑处理。

2.Servlet调用forword()方法,服务器Servlet把目标资源返回给客户端浏览器。

请求转发
注:请求转发会返回到资源的相对目录下

重定向

两次请求,两次转发
response.sendRedirect(URL地址)
处理流程:

1.客户端发送请求,Servlet做出业务逻辑处理。
2.Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器(web客户端)。
3.客户端浏览器重新访问服务器资源xxx.jsp,
4.服务器再次对客户端浏览器做出响应。

重定向
注:重定向能调用在controller中对应返回地址的方法

cookie 是服务器端保存在浏览器的一小段文本信息,浏览器每次向服务器端发出请求,都会附带上这段信息

使用场景:

  • 对话管理:保存登录、购物车等需要记录的信息
  • 个性化:保存用户的偏好,比如网页的字体大小、背景色等等
  • 追踪:记录和分析用户的行为

Cookie的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CookieUtils {

public static String getCookie(HttpServletRequest request,String cookieName){

Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
if(cookie.getName().equals(cookieName)){
return cookie.getValue();
}
}
}
return null;
}

public static void writeCookie(HttpServletResponse response, String cookieName,String value){
Cookie cookie = new Cookie(cookieName,value);
// 只能资源目录下能使用Cookie
cookie.setPath("/");
cookie.setMaxAge(3600);
response.addCookie(cookie);
}

}

Seesion 和 Cookie的结合应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@GetMapping("/page")
public String home() {
return "login";
}

@GetMapping
public String login(@CookieValue(value = "token", required = false) Cookie cookie) {
if (cookie != null) {
//如果cookie不为空则说明已经d登陆 则直接跳转主界面
return "/index";
}
//TODO 重定向次数过多 使用redirect,会再次调用controller层的login方法
return "redirect:/login/page";
}

/**
* 登录方法
*/
@PostMapping
public String login(UserInfo userInfo, HttpSession session, HttpServletResponse response, ModelMap map) {
UserInfo user = userInfoService.findOneUser(userInfo);
//判断用户名密码是否正确
if (user != null) {
session.setAttribute(ApplicationConst.LOGIN_SESSION_STATUS, user);
//生成token
String token = UUID.randomUUID().toString();
//创建cookie
Cookie cookie = new Cookie("token", token);
// 3、设置 cookie 的有效时间,就浏览器关闭不会清楚此Cookie,但是谷歌浏览器依旧删除了:
// 设置有效期 单位是秒,不是毫秒
// 默认情况下创建的 cookie 是一个会话级别的 cookie,即存储在浏览器内存中,浏览器关闭,cookie 消失。
// 正整数:表示将 cookie 保存到浏览器的缓存目录(硬盘)中,数值表示保存的时间;
// 负整数:表示将 cookie 保存到浏览器的内存中,浏览器关闭 cookie 就会销毁;
// 0:表示删除同名的 cookie,删除 cookie 时,有效路径必须一致,否则不会删除
cookie.setMaxAge(20 * 60);
//将cookie响应给浏览器
response.addCookie(cookie);
return "index";
} else {
map.put("msg", "账号或密码错误");
return "redirect:/login/page";
}
}

@GetMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/login/page";
}

数组

Arrays.toString(数组)

  • Arrays类中只可以用toString()方法进行遍历一维数组,而不可以用deepToString(Object a)

  • 操作一维数组:

    int[] arr = new int[]{1,2,3};
    输出:[1, 2, 3]

  • 操作二维数组:

    • 输出的是数组的地址:eg:[[I@7a7b0070, [I@39a054a5

    • 拼接步骤:

      • 1.如果不为空且length大于0
      • 2.采用StringBuilder b = new StringBuilder();
      • 3.拼接b.append(‘[‘);
      • 4.循环每一行:for (int i = 0; ; i++)
      • 5.调用String.valueOf():

      return getClass().getName() + “@” + Integer.toHexString(hashCode());

      • 6.循环到最后一行:return b.append(‘]’).toString();
  • 源码展示

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public static String toString(int[] a) {
    if (a == null)
    return "null";
    int iMax = a.length - 1;
    if (iMax == -1)
    return "[]";

    StringBuilder b = new StringBuilder();
    b.append('[');
    for (int i = 0; ; i++) {
    b.append(a[i]);
    if (i == iMax)
    return b.append(']').toString();
    b.append(", ");
    }
    }

    Arrays.deepToString(数组))

  • 不仅可以遍历二维,还可以遍历三维甚至更高.

    返回指定数组“深层内容”的字符串表示形式。如果数组包含作为元素的其他数组,则字符串表示形式包含其内容等。此方法是为了将多维数组转换为字符串而设计的。
    字符串表示形式由数组的元素列表组成,括在方括号(”[]”)中。相邻元素用字符 “, “(逗号加空格)分隔。这些元素通过 String.valueOf(Object) 转换为字符串,除非它们是自身的数组。

1
2
3
4
5
6
7
8
9
10
11
public static String deepToString(Object[] a) {
if (a == null)
return "null";

int bufLen = 20 * a.length;
if (a.length != 0 && bufLen <= 0)
bufLen = Integer.MAX_VALUE;
StringBuilder buf = new StringBuilder(bufLen);
deepToString(a, buf, new HashSet<Object[]>());
return buf.toString();
}

String、Stringbuffer与Stringbuilder的区别

在执行速度上:

  • Stringbuilder->Stringbuffer->String

    String是字符串常量

  • Stringbuffer是字符串变量
  • Stringbuilder是字符串变量
    • 有可能我们会疑惑String怎么是字符串变量。看以下代码:
      String str = adc;
      str = str + “ef”;
      System.out.println(str);
      输出结果为:abcef;

      在Java虚拟机中str为adc时是一个变量,当str被重新赋值为adcef时为另一个变量,被重新分配了一次内存,上次使用的内存会被gc在适当的时候回收掉。由于这种机制导致了如果有大量的String赋值操作时,会导致运行速度的缓慢,以及内存使用量的上升。

  • 一个特殊的例子
    • 你会很惊讶的发现,生成str对象速度简直太快了,而这个时候Stringbuffer居然速度上根本一点都不占优势。其实这是JVM的一个把戏,实际上:
      String str = ”this is only a“ + “simple” + “test”;
      其实就是
      String str = “this is only a simple test”;
      所以不需要太多的是时间。但大家这里需要注意的是,如果你的字符串是来自另外的String对象的话。速度就没那么快了,譬如:
      String str1 = “this is only a”;
      String str2 = “simple”;
      String str3 = “test”;
      String str = str1 + str2 + str3;
      这时候JVM会规规矩矩的按照原来的方式去做。
  • StringBuilder与StringBuffer
    StringBuilder:线程非安全的
    StringBuffer:线程安全的

    当我们在字符串缓冲区去被多个线程使用时,JVM不能保证 StringBuilder的线程是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。
    当然大多数情况是在单线程下进行的,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。

  • 小结:
    (1)如果要操作少量的数据用 String;
    (2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
    (3)单线程操作字符串缓冲区下操作大量数据 StringBuilder(推荐使用)。


打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  1. © 2020 Liu Yang    湘ICP备20003709号

请我喝杯咖啡吧~

支付宝
微信