1.hashMap与hashTable
Java中数据存储方式最底层的两种结构,一种是数组,另一种就是链表,数组的特点:连续空间,寻址迅速,但是在删除或者添加元素的时候需要有较大幅度的移动,所以查询速度快,增删较慢。而链表正好相反,由于空间不连续,寻址困难,增删元素只需修改指针,所以查询慢、增删快。有没有一种数据结构来综合一下数组和链表,以便发挥他们各自的优势?答案是肯定的!就是:哈希表。哈希表具有较快(常量级)的查询速度,及相对较快的增删速度,所以很适合在海量数据的环境中使用。一般实现哈希表的方法采用“拉链法”,我们可以理解为“链表的数组”,如下图:
从上图中,我们可以发现哈希表是由数组 链表组成的,一个长度为16的数组中,每个元素存储的是一个链表的头结点。那么这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置。
1.1 关于hashMap更详细的内容见:HashMap的存储与实现
1.2 HashTable的内部存储结构
HashTable和HashMap采用相同的存储机制,二者的实现基本一致,不同的是: 1.HashMap是非线程安全的,HashTable是线程安全的,内部的方法基本都是synchronized。 2.HashTable不允许有null值的存在,而hashMap则允许key或value为null。在HashTable中调用put方法时,如果key为null,直接抛出NullPointerException。其它细微的差别还有,比如初始化Entry数组的大小等等,但基本思想和HashMap一样。
2.遍历map的4种方式的比较
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
3.Java中多线程
http://www.cnblogs.com/lwbqqyumidi/p/3804883.html4.Java连接Oracle
这是道经常被写的面试题,http://m.blog.csdn.net/article/details?id=9068765,同时需要掌握socket的长连接和短连接;socket的同步和异步。
5.Java8中的新特性:stream
5.1利用stream将List转为Map
5.2stream中常用几个API
//java8利用sream中map函数实现list转list
public List<Long> getIdList(List<Account> accounts) {
return accounts.stream().map(Account::getId).collect(Collectors.toList());
//return accounts.stream().map(Account->Account.getId).collect(Collectors.toList());
}
5.3利用stream将Map转为List
//利用Java8中Stream接口map处理函数,将Map集合转为List
private static void convert_map_to_list_with_java8_lambda() {
Map<Integer, Movie> movieMap = new HashMap<Integer, Movie>();
movieMap.put(1, new Movie(1, "a"));
movieMap.put(2, new Movie(2, "b"));
movieMap.put(3, new Movie(3, "c"));
//将Map集合中所有的value值构建一个List
List<Movie> movieList = movieMap.entrySet().stream().map(o->o.getValue()).collect(Collectors.toList());
for (Movie movie:movieList) {
System.out.println(movie.getMoveName());
}
//利用Java8中forEach和lambda特性循环遍历输出
movieList.forEach(movie -> System.out.println(movie));
}
5.4 Java8新特性全搜罗
6.常用的非空判断
6.1字符串非空判断
org.apache.commons.lang3.StringUtils.StringUtils.isNoneEmpty(str);
其实,在spring的框架中也有一个StringUtils工具类包。
6.2集合非空判断
org.springframework.util.CollectionUtils.isEmpty(list);
6.3 对象非空判断
obj != null;
7.Java8中的新特性:Lambda表达式
结合代码理解,如下:
package com.xiaojukeji.multiThread;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* Description:
1.java8函数式接口:关于概念自行百度查询
下面是 Java SE 7 中已经存在的函数式接口:
java.lang.Runnable
java.util.concurrent.Callable
java.security.PrivilegedAction
java.util.Comparator
java.io.FileFilter
java.beans.PropertyChangeListener
除此之外,Java SE 8中增加了一个新的包:java.util.function,它里面包含了常用的函数式接口,例如:
Predicate<T>——接收 T 并返回 boolean
Consumer<T>——接收 T,不返回值
Function<T, R>——接收 T,返回 R
Supplier<T>——提供 T 对象(例如工厂),不接收值
UnaryOperator<T>——接收 T 对象,返回 T
BinaryOperator<T>——接收两个 T,返回 T
除了以上JDK以实现的函数式接口外,我们也可以自定义函数式接口;
2.Lamdba表达式的返回值就是以上函数式接口的某一种,也就是说lambda表达式返回值是函数式接口,
至于具体是哪一种函数式接口,则由java8根据上下文语义自行匹配,正是这种自适应匹配的能力,我们也可
将lambda返回值的类型称为"目标类型";
3.以下面ThreadApi类为例:
Runnable runnable = () -> {threadApi.m();};
new Tread(runnable).start;
即:() -> {threadApi.m();}返回值是一个只包含run一个方法的Runnable类型的函数式接口;
* Created by Guo_guo on 2017-7-16.
*/
public class ThreadApi {
public /*volatile*/ int count = 0;
public /*synchronized*/ void m (){
for (int i=0; i<10000; i++) {
count++;
}
}
public static void main(String[] args) {
ThreadApi threadApi = new ThreadApi();
List<Thread> threadList = new ArrayList<>(10);
for (int i=0; i<10; i++) {
//java8 lambda表达式构建线程,注意此处的ThreadApi没必要继承Runnable接口;
//() -> threadApi.m()的返回值是Runnable函数式接口
threadList.add(new Thread(() -> threadApi.m(), "thread-"+i) );
/*threadList.add(new Thread(
new Runnable() {
@Override
public void run() {
threadApi.m();
}
}
)//new Thread
);//.add
*/
/*
函数式接口:lanbda表达式返回值类型是一种函数式接口,
由于Java8中定义的函数式接口有多种类型,而lamdba表达式返回值能自适应目标类型,所以
也亦可将lambda表达式返回值的类型称之为"目标类型";
下面的例子中,(x) -> {System.out.print(x+": ");return "Function";}
返回值是Function类型的函数式接口类型,而在Function函数式接口类型中只有一个apply函数;
*/
Function<String,String> function = (x) -> {System.out.print(x+": ");return "Function";};
System.out.println(function.apply("hello world"));
}
threadList.forEach(obj -> obj.start());
threadList.forEach(obj -> {
try {
obj.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(threadApi.count);
}
}
备注:关于Java中常见的一些坑或错误点,向大家推荐一本书,人民邮电出版社李刚主编的《疯狂Java:突破程序员基本功的16课》