From 9ed8e30f5f657a94cc4afd35ef1da148712b2eaf Mon Sep 17 00:00:00 2001 From: ciphermagic Date: Mon, 1 Jun 2020 01:15:19 +0800 Subject: [PATCH 01/10] fixed --- sandbox/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sandbox/pom.xml b/sandbox/pom.xml index 1313737..f0f4c1c 100644 --- a/sandbox/pom.xml +++ b/sandbox/pom.xml @@ -122,8 +122,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 8 + 8 From 5c62c26960268612689f9804b9d2de9dd62a942e Mon Sep 17 00:00:00 2001 From: ciphermagic Date: Thu, 4 Jun 2020 17:37:29 +0800 Subject: [PATCH 02/10] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{CheckParamAspect.java => Checker.java} | 860 ++++++++++-------- 1 file changed, 471 insertions(+), 389 deletions(-) rename sandbox/src/main/java/com/cipher/checker/{CheckParamAspect.java => Checker.java} (51%) diff --git a/sandbox/src/main/java/com/cipher/checker/CheckParamAspect.java b/sandbox/src/main/java/com/cipher/checker/Checker.java similarity index 51% rename from sandbox/src/main/java/com/cipher/checker/CheckParamAspect.java rename to sandbox/src/main/java/com/cipher/checker/Checker.java index 0617d7a..85654f8 100644 --- a/sandbox/src/main/java/com/cipher/checker/CheckParamAspect.java +++ b/sandbox/src/main/java/com/cipher/checker/Checker.java @@ -1,389 +1,471 @@ -package com.cipher.checker; - -import org.apache.commons.lang3.StringUtils; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.reflect.MethodSignature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.function.BiFunction; - -/** - * 参数校验 切面 - * - * @author cipher - * @date 2017年11月7日 - */ -@Aspect -public class CheckParamAspect { - - private static final Logger LOG = LoggerFactory.getLogger(CheckParamAspect.class); - - @Around(value = "@com.cipher.checker.Check") // 这里要换成自定义注解的路径 - public Object check(ProceedingJoinPoint point) throws Throwable { - Object obj; - // 参数校验 - String msg = doCheck(point); - if (!StringUtils.isEmpty(msg)) { - // 这里可以返回自己封装的返回类,例如:return ResultBuilder.unsuccess(msg); - throw new IllegalArgumentException(msg); - } - // 通过校验,继续执行原有方法 - obj = point.proceed(); - return obj; - } - - /** - * 参数校验 - * - * @param point ProceedingJoinPoint - * @return 错误信息 - */ - private String doCheck(ProceedingJoinPoint point) { - // 获取方法参数值 - Object[] arguments = point.getArgs(); - // 获取方法 - Method method = getMethod(point); - // 默认的错误信息 - String methodInfo = StringUtils.isEmpty(method.getName()) ? "" : " while calling " + method.getName(); - String msg = ""; - if (isCheck(method, arguments)) { - Check annotation = method.getAnnotation(Check.class); - String[] fields = annotation.value(); - // 只支持对第一个参数进行校验 - Object vo = arguments[0]; - if (vo == null) { - msg = "param can not be null"; - } else { - for (String field : fields) { - // 解析字段 - FieldInfo info = resolveField(field, methodInfo); - // 获取字段的值 - Object value = ReflectionUtil.invokeGetter(vo, info.field); - // 执行校验规则 - Boolean isValid = info.optEnum.fun.apply(value, info.operatorNum); - msg = isValid ? msg : info.innerMsg; - } - } - } - return msg; - } - - /** - * 解析字段 - * - * @param fieldStr 字段字符串 - * @param methodInfo 方法信息 - * @return 字段信息实体类 - */ - private FieldInfo resolveField(String fieldStr, String methodInfo) { - FieldInfo fieldInfo = new FieldInfo(); - String innerMsg = ""; - // 解析提示信息 - if (fieldStr.contains(SEPARATOR)) { - innerMsg = fieldStr.split(SEPARATOR)[1]; - fieldStr = fieldStr.split(SEPARATOR)[0]; - } - // 解析操作符 - if (fieldStr.contains(Operator.GREATER_THAN_EQUAL.value)) { - fieldInfo.optEnum = Operator.GREATER_THAN_EQUAL; - } else if (fieldStr.contains(Operator.LESS_THAN_EQUAL.value)) { - fieldInfo.optEnum = Operator.LESS_THAN_EQUAL; - } else if (fieldStr.contains(Operator.GREATER_THAN.value)) { - fieldInfo.optEnum = Operator.GREATER_THAN; - } else if (fieldStr.contains(Operator.LESS_THAN.value)) { - fieldInfo.optEnum = Operator.LESS_THAN; - } else if (fieldStr.contains(Operator.NOT_EQUAL.value)) { - fieldInfo.optEnum = Operator.NOT_EQUAL; - } else { - fieldInfo.optEnum = Operator.NOT_NULL; - } - // 不等于空,直接赋值字段 - if (fieldInfo.optEnum == Operator.NOT_NULL) { - fieldInfo.field = fieldStr; - fieldInfo.operatorNum = ""; - } - // 其他操作符,需要分离出字段和操作数 - else { - fieldInfo.field = fieldStr.split(fieldInfo.optEnum.value)[0]; - fieldInfo.operatorNum = fieldStr.split(fieldInfo.optEnum.value)[1]; - } - fieldInfo.operator = fieldInfo.optEnum.value; - // 处理错误信息 - String defaultMsg = fieldInfo.field + " must " + fieldInfo.operator + " " + fieldInfo.operatorNum + methodInfo; - fieldInfo.innerMsg = StringUtils.isEmpty(innerMsg) ? defaultMsg : innerMsg; - return fieldInfo; - } - - // -=================== 对不同类型的值进行校验 起 ======================= - - /** - * 是否不为空 - * - * @param value 字段值 - * @param operatorNum 操作数,这里不需要,只是为了参数统一 - * @return 是否不为空 - */ - private static Boolean isNotNull(Object value, String operatorNum) { - Boolean isNotNull = Boolean.TRUE; - Boolean isStringNull = (value instanceof String) && StringUtils.isEmpty((String) value); - Boolean isCollectionNull = (value instanceof Collection) && CollectionUtils.isEmpty((Collection) value); - if (value == null) { - isNotNull = Boolean.FALSE; - } else if (isStringNull || isCollectionNull) { - isNotNull = Boolean.FALSE; - } - return isNotNull; - } - - /** - * 是否大于 - * - * @param value 字段值 - * @param operatorNum 操作数 - * @return 是否大于 - */ - private static Boolean isGreaterThan(Object value, String operatorNum) { - Boolean isGreaterThan = Boolean.FALSE; - if (value == null) { - return Boolean.FALSE; - } - Boolean isStringGreaterThen = (value instanceof String) && ((String) value).length()> Integer.valueOf(operatorNum); - Boolean isLongGreaterThen = (value instanceof Long) && ((Long) value)> Long.valueOf(operatorNum); - Boolean isIntegerGreaterThen = (value instanceof Integer) && ((Integer) value)> Integer.valueOf(operatorNum); - Boolean isShortGreaterThen = (value instanceof Short) && ((Short) value)> Short.valueOf(operatorNum); - Boolean isFloatGreaterThen = (value instanceof Float) && ((Float) value)> Float.valueOf(operatorNum); - Boolean isDoubleGreaterThen = (value instanceof Double) && ((Double) value)> Double.valueOf(operatorNum); - Boolean isCollectionGreaterThen = (value instanceof Collection) && ((Collection) value).size()> Integer.valueOf(operatorNum); - if (isStringGreaterThen || isLongGreaterThen || isIntegerGreaterThen || - isShortGreaterThen || isFloatGreaterThen || isDoubleGreaterThen || isCollectionGreaterThen) { - isGreaterThan = Boolean.TRUE; - } - return isGreaterThan; - } - - /** - * 是否大于等于 - * - * @param value 字段值 - * @param operatorNum 操作数 - * @return 是否大于等于 - */ - private static Boolean isGreaterThanEqual(Object value, String operatorNum) { - Boolean isGreaterThanEqual = Boolean.FALSE; - if (value == null) { - return Boolean.FALSE; - } - Boolean isStringGreaterThenEqual = (value instanceof String) && ((String) value).length()>= Integer.valueOf(operatorNum); - Boolean isLongGreaterThenEqual = (value instanceof Long) && ((Long) value)>= Long.valueOf(operatorNum); - Boolean isIntegerGreaterThenEqual = (value instanceof Integer) && ((Integer) value)>= Integer.valueOf(operatorNum); - Boolean isShortGreaterThenEqual = (value instanceof Short) && ((Short) value)>= Short.valueOf(operatorNum); - Boolean isFloatGreaterThenEqual = (value instanceof Float) && ((Float) value)>= Float.valueOf(operatorNum); - Boolean isDoubleGreaterThenEqual = (value instanceof Double) && ((Double) value)>= Double.valueOf(operatorNum); - Boolean isCollectionGreaterThenEqual = (value instanceof Collection) && ((Collection) value).size()>= Integer.valueOf(operatorNum); - if (isStringGreaterThenEqual || isLongGreaterThenEqual || isIntegerGreaterThenEqual || - isShortGreaterThenEqual || isFloatGreaterThenEqual || isDoubleGreaterThenEqual || isCollectionGreaterThenEqual) { - isGreaterThanEqual = Boolean.TRUE; - } - return isGreaterThanEqual; - } - - /** - * 是否少于 - * - * @param value 字段值 - * @param operatorNum 操作数 - * @return 是否少于 - */ - private static Boolean isLessThan(Object value, String operatorNum) { - Boolean isLessThan = Boolean.FALSE; - if (value == null) { - return Boolean.FALSE; - } - Boolean isStringLessThen = (value instanceof String) && ((String) value).length() < Integer.valueOf(operatorNum); - Boolean isLongLessThen = (value instanceof Long) && ((Long) value) < Long.valueOf(operatorNum); - Boolean isIntegerLessThen = (value instanceof Integer) && ((Integer) value) < Integer.valueOf(operatorNum); - Boolean isShortLessThen = (value instanceof Short) && ((Short) value) < Short.valueOf(operatorNum); - Boolean isFloatLessThen = (value instanceof Float) && ((Float) value) < Float.valueOf(operatorNum); - Boolean isDoubleLessThen = (value instanceof Double) && ((Double) value) < Double.valueOf(operatorNum); - Boolean isCollectionLessThen = (value instanceof Collection) && ((Collection) value).size() < Integer.valueOf(operatorNum); - if (isStringLessThen || isLongLessThen || isIntegerLessThen || - isShortLessThen || isFloatLessThen || isDoubleLessThen || isCollectionLessThen) { - isLessThan = Boolean.TRUE; - } - return isLessThan; - } - - /** - * 是否少于等于 - * - * @param value 字段值 - * @param operatorNum 操作数 - * @return 是否少于等于 - */ - private static Boolean isLessThanEqual(Object value, String operatorNum) { - Boolean isLessThanEqual = Boolean.FALSE; - if (value == null) { - return Boolean.FALSE; - } - Boolean isStringLessThenEqual = (value instanceof String) && ((String) value).length() <= Integer.valueOf(operatorNum); - Boolean isLongLessThenEqual = (value instanceof Long) && ((Long) value) <= Long.valueOf(operatorNum); - Boolean isIntegerLessThenEqual = (value instanceof Integer) && ((Integer) value) <= Integer.valueOf(operatorNum); - Boolean isShortLessThenEqual = (value instanceof Short) && ((Short) value) <= Short.valueOf(operatorNum); - Boolean isFloatLessThenEqual = (value instanceof Float) && ((Float) value) <= Float.valueOf(operatorNum); - Boolean isDoubleLessThenEqual = (value instanceof Double) && ((Double) value) <= Double.valueOf(operatorNum); - Boolean isCollectionLessThenEqual = (value instanceof Collection) && ((Collection) value).size() <= Integer.valueOf(operatorNum); - if (isStringLessThenEqual || isLongLessThenEqual || isIntegerLessThenEqual || - isShortLessThenEqual || isFloatLessThenEqual || isDoubleLessThenEqual || isCollectionLessThenEqual) { - isLessThanEqual = Boolean.TRUE; - } - return isLessThanEqual; - } - - /** - * 是否不等于 - * - * @param value 字段值 - * @param operatorNum 操作数 - * @return 是否不等于 - */ - private static Boolean isNotEqual(Object value, String operatorNum) { - Boolean isNotEqual = Boolean.FALSE; - if (value == null) { - return Boolean.FALSE; - } - Boolean isStringNotEqual = (value instanceof String) && !value.equals(operatorNum); - Boolean isLongNotEqual = (value instanceof Long) && !value.equals(Long.valueOf(operatorNum)); - Boolean isIntegerNotEqual = (value instanceof Integer) && !value.equals(Integer.valueOf(operatorNum)); - Boolean isShortNotEqual = (value instanceof Short) && !value.equals(Short.valueOf(operatorNum)); - Boolean isFloatNotEqual = (value instanceof Float) && !value.equals(Float.valueOf(operatorNum)); - Boolean isDoubleNotEqual = (value instanceof Double) && !value.equals(Double.valueOf(operatorNum)); - Boolean isCollectionNotEqual = (value instanceof Collection) && ((Collection) value).size() != Integer.valueOf(operatorNum); - if (isStringNotEqual || isLongNotEqual || isIntegerNotEqual || - isShortNotEqual || isFloatNotEqual || isDoubleNotEqual || isCollectionNotEqual) { - isNotEqual = Boolean.TRUE; - } - return isNotEqual; - } - - // -=================== 对不同类型的值进行校验 止 ======================= - - /** - * 判断是否符合参数规则 - * - * @param method 方法 - * @param arguments 方法参数 - * @return 是否符合 - */ - private Boolean isCheck(Method method, Object[] arguments) { - Boolean isCheck = Boolean.TRUE; - // 只允许有一个参数 - if (!method.isAnnotationPresent(Check.class) - || arguments == null - || arguments.length != 1) { - isCheck = Boolean.FALSE; - } - return isCheck; - } - - /** - * 获取方法 - * - * @param joinPoint ProceedingJoinPoint - * @return 方法 - */ - private Method getMethod(ProceedingJoinPoint joinPoint) { - MethodSignature signature = (MethodSignature) joinPoint.getSignature(); - Method method = signature.getMethod(); - if (method.getDeclaringClass().isInterface()) { - try { - method = joinPoint - .getTarget() - .getClass() - .getDeclaredMethod(joinPoint.getSignature().getName(), - method.getParameterTypes()); - } catch (SecurityException | NoSuchMethodException e) { - LOG.error("" + e); - } - } - return method; - } - - /** - * 字段信息 - */ - class FieldInfo { - /** - * 字段 - */ - String field; - /** - * 提示信息 - */ - String innerMsg; - /** - * 操作符 - */ - String operator; - /** - * 操作数 - */ - String operatorNum; - /** - * 操作枚举 - */ - Operator optEnum; - } - - /** - * 操作枚举,封装操作符和对应的校验规则 - */ - enum Operator { - /** - * 大于 - */ - GREATER_THAN(">", CheckParamAspect::isGreaterThan), - /** - * 大于等于 - */ - GREATER_THAN_EQUAL(">=", CheckParamAspect::isGreaterThanEqual), - /** - * 小于 - */ - LESS_THAN("<", CheckParamAspect::isLessThan), - /** - * 小于等于 - */ - LESS_THAN_EQUAL("<=", CheckParamAspect::isLessThanEqual), - /** - * 不等于 - */ - NOT_EQUAL("!=", CheckParamAspect::isNotEqual), - /** - * 不为空 - */ - NOT_NULL("not null", CheckParamAspect::isNotNull); - - private String value; - - /** - * BiFunction:接收字段值(Object)和操作数(String),返回是否符合规则(Boolean) - */ - private BiFunction fun; - - Operator(String value, BiFunction fun) { - this.value = value; - this.fun = fun; - } - } - - // -====================== 常量 ========================= - - private static final String SEPARATOR = ":"; - -} +package com.cipher.checker; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * 参数校验 切面 + * + * @author cipher + * @date 2017/11/7 + */ +@Aspect +public class Checker { + + // -====================== constant ========================= + + private static final String SPLITOR = ":"; + + // -====================== log ========================= + + private static final Logger LOG = LoggerFactory.getLogger(Checker.class); + + private ExpressionParser parser = new SpelExpressionParser(); + private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); + private Function unsuccess; + + private Checker() { + } + + /** + * Action performed when check fails + * + * @param unsuccess lambda of the action + */ + public void setUnsuccess(Function unsuccess) { + this.unsuccess = unsuccess; + } + + /** + * checker builder + */ + public static class Builder { + private Checker checker = new Checker(); + + public Builder unsuccess(Function unsuccess) { + checker.setUnsuccess(unsuccess); + return this; + } + + public Checker build() { + return checker; + } + } + + /** + * initialize builder + * + * @return checker builder + * @see Builder + */ + public static Builder builder() { + return new Builder(); + } + + /** + * aop around the method + * + * @param point ProceedingJoinPoint + * @return method result + * @throws Throwable method exception + */ + @Around(value = "@annotation(cn.ciphermagic.common.checker.Check)") + public Object check(ProceedingJoinPoint point) throws Throwable { + Object obj; + // check param + String msg = doCheck(point); + if (!StringUtils.isEmpty(msg)) { + return unsuccess.apply(msg); + } + obj = point.proceed(); + return obj; + } + + /** + * check param + * + * @param point ProceedingJoinPoint + * @return error message + */ + private String doCheck(ProceedingJoinPoint point) { + // get arguments + Object[] arguments = point.getArgs(); + // get method + Method method = getMethod(point); + String methodInfo = StringUtils.isEmpty(method.getName()) ? "" : " while calling " + method.getName(); + String msg = ""; + if (isCheck(method, arguments)) { + Check annotation = method.getAnnotation(Check.class); + String[] fields = annotation.value(); + Object vo = arguments[0]; + if (vo == null) { + msg = "param can not be null"; + } else { + for (String field : fields) { + FieldInfo info = resolveField(field, methodInfo); + Boolean isValid; + if (info.optEnum == Operator.SPEL) { + isValid = parseSpel(method, arguments, info.field); + } else { + String getMethodName = "get" + StringUtils.capitalize(info.field); + Method getMethod = ReflectionUtils.findMethod(vo.getClass(), getMethodName); + Object value = ReflectionUtils.invokeMethod(getMethod, vo); + isValid = info.optEnum.fun.apply(value, info.operatorNum); + } + if (!isValid) { + msg = info.innerMsg; + break; + } + } + } + } + return msg; + } + + /** + * parse spel expression + * + * @param method method + * @param arguments arguments + * @param spel spel expression + * @return is match + */ + private Boolean parseSpel(Method method, Object[] arguments, String spel) { + String[] params = discoverer.getParameterNames(method); + EvaluationContext context = new StandardEvaluationContext(); + for (int len = 0; len < params.length; len++) { + context.setVariable(params[len], arguments[len]); + } + try { + Expression expression = parser.parseExpression(spel); + return expression.getValue(context, Boolean.class); + } catch (Exception e) { + LOG.error("", e); + return Boolean.FALSE; + } + } + + /** + * parse field + * + * @param fieldStr field string + * @param methodInfo method info + * @return the entity contain field's info + */ + private FieldInfo resolveField(String fieldStr, String methodInfo) { + FieldInfo fieldInfo = new FieldInfo(); + String innerMsg = ""; + // parse error message + if (fieldStr.contains(SPLITOR)) { + if (fieldStr.split(SPLITOR).length == 2) { + innerMsg = fieldStr.split(SPLITOR)[1].trim(); + fieldStr = fieldStr.split(SPLITOR)[0].trim(); + } else { + throw new IllegalArgumentException("@Check annotation error: " + fieldStr); + } + } + // parse operator + if (fieldStr.startsWith("#")) { + fieldInfo.optEnum = Operator.SPEL; + } else if (fieldStr.contains(Operator.GREATER_THAN_EQUAL.value)) { + fieldInfo.optEnum = Operator.GREATER_THAN_EQUAL; + } else if (fieldStr.contains(Operator.LESS_THAN_EQUAL.value)) { + fieldInfo.optEnum = Operator.LESS_THAN_EQUAL; + } else if (fieldStr.contains(Operator.GREATER_THAN.value)) { + fieldInfo.optEnum = Operator.GREATER_THAN; + } else if (fieldStr.contains(Operator.LESS_THAN.value)) { + fieldInfo.optEnum = Operator.LESS_THAN; + } else if (fieldStr.contains(Operator.NOT_EQUAL.value)) { + fieldInfo.optEnum = Operator.NOT_EQUAL; + } else { + fieldInfo.optEnum = Operator.NOT_NULL; + } + // direct assignment field + if (fieldInfo.optEnum == Operator.NOT_NULL || fieldInfo.optEnum == Operator.SPEL) { + fieldInfo.field = fieldStr; + } + // other operators, need to separate fields and operands + else { + fieldInfo.field = fieldStr.split(fieldInfo.optEnum.value)[0]; + fieldInfo.operatorNum = fieldStr.split(fieldInfo.optEnum.value)[1]; + } + fieldInfo.operator = fieldInfo.optEnum.value; + String operatorNum = fieldInfo.operatorNum == null ? "" : " " + fieldInfo.operatorNum; + String defaultMsg = fieldInfo.field + " must " + fieldInfo.operator + operatorNum + methodInfo; + fieldInfo.innerMsg = StringUtils.isEmpty(innerMsg) ? defaultMsg : innerMsg; + return fieldInfo; + } + + /** + * is not null + * + * @param value field's value + * @param operatorNum the num of operator + * @return is not null + */ + private static Boolean isNotNull(Object value, String operatorNum) { + Boolean isNotNull = Boolean.TRUE; + Boolean isStringNull = (value instanceof String) && StringUtils.isEmpty(value); + Boolean isCollectionNull = (value instanceof Collection) && CollectionUtils.isEmpty((Collection) value); + if (value == null) { + isNotNull = Boolean.FALSE; + } else if (isStringNull || isCollectionNull) { + isNotNull = Boolean.FALSE; + } + return isNotNull; + } + + /** + * is greater than + * + * @param value field value + * @param operatorNum operatorNum + * @return is greater than + */ + private static Boolean isGreaterThan(Object value, String operatorNum) { + Boolean isGreaterThan = Boolean.FALSE; + if (value == null) { + return Boolean.FALSE; + } + boolean isStringGreaterThen = (value instanceof String) && ((String) value).length()> Integer.valueOf(operatorNum); + boolean isLongGreaterThen = (value instanceof Long) && ((Long) value)> Long.valueOf(operatorNum); + boolean isIntegerGreaterThen = (value instanceof Integer) && ((Integer) value)> Integer.valueOf(operatorNum); + boolean isShortGreaterThen = (value instanceof Short) && ((Short) value)> Short.valueOf(operatorNum); + boolean isFloatGreaterThen = (value instanceof Float) && ((Float) value)> Float.valueOf(operatorNum); + boolean isDoubleGreaterThen = (value instanceof Double) && ((Double) value)> Double.valueOf(operatorNum); + boolean isCollectionGreaterThen = (value instanceof Collection) && ((Collection) value).size()> Integer.valueOf(operatorNum); + if (isStringGreaterThen || isLongGreaterThen || isIntegerGreaterThen || + isShortGreaterThen || isFloatGreaterThen || isDoubleGreaterThen || isCollectionGreaterThen) { + isGreaterThan = Boolean.TRUE; + } + return isGreaterThan; + } + + /** + * is greater than or equal to + * + * @param value field value + * @param operatorNum operatorNum + * @return is greater than or equal to + */ + private static Boolean isGreaterThanEqual(Object value, String operatorNum) { + Boolean isGreaterThanEqual = Boolean.FALSE; + if (value == null) { + return Boolean.FALSE; + } + boolean isStringGreaterThenEqual = (value instanceof String) && ((String) value).length()>= Integer.valueOf(operatorNum); + boolean isLongGreaterThenEqual = (value instanceof Long) && ((Long) value)>= Long.valueOf(operatorNum); + boolean isIntegerGreaterThenEqual = (value instanceof Integer) && ((Integer) value)>= Integer.valueOf(operatorNum); + boolean isShortGreaterThenEqual = (value instanceof Short) && ((Short) value)>= Short.valueOf(operatorNum); + boolean isFloatGreaterThenEqual = (value instanceof Float) && ((Float) value)>= Float.valueOf(operatorNum); + boolean isDoubleGreaterThenEqual = (value instanceof Double) && ((Double) value)>= Double.valueOf(operatorNum); + boolean isCollectionGreaterThenEqual = (value instanceof Collection) && ((Collection) value).size()>= Integer.valueOf(operatorNum); + if (isStringGreaterThenEqual || isLongGreaterThenEqual || isIntegerGreaterThenEqual || + isShortGreaterThenEqual || isFloatGreaterThenEqual || isDoubleGreaterThenEqual || isCollectionGreaterThenEqual) { + isGreaterThanEqual = Boolean.TRUE; + } + return isGreaterThanEqual; + } + + /** + * is less than + * + * @param value field value + * @param operatorNum operatorNum + * @return is less than + */ + private static Boolean isLessThan(Object value, String operatorNum) { + Boolean isLessThan = Boolean.FALSE; + if (value == null) { + return Boolean.FALSE; + } + boolean isStringLessThen = (value instanceof String) && ((String) value).length() < Integer.valueOf(operatorNum); + boolean isLongLessThen = (value instanceof Long) && ((Long) value) < Long.valueOf(operatorNum); + boolean isIntegerLessThen = (value instanceof Integer) && ((Integer) value) < Integer.valueOf(operatorNum); + boolean isShortLessThen = (value instanceof Short) && ((Short) value) < Short.valueOf(operatorNum); + boolean isFloatLessThen = (value instanceof Float) && ((Float) value) < Float.valueOf(operatorNum); + boolean isDoubleLessThen = (value instanceof Double) && ((Double) value) < Double.valueOf(operatorNum); + boolean isCollectionLessThen = (value instanceof Collection) && ((Collection) value).size() < Integer.valueOf(operatorNum); + if (isStringLessThen || isLongLessThen || isIntegerLessThen || + isShortLessThen || isFloatLessThen || isDoubleLessThen || isCollectionLessThen) { + isLessThan = Boolean.TRUE; + } + return isLessThan; + } + + /** + * is less than or equal to + * + * @param value field value + * @param operatorNum operatorNum + * @return is less than or equal to + */ + private static Boolean isLessThanEqual(Object value, String operatorNum) { + Boolean isLessThanEqual = Boolean.FALSE; + if (value == null) { + return Boolean.FALSE; + } + boolean isStringLessThenEqual = (value instanceof String) && ((String) value).length() <= Integer.valueOf(operatorNum); + boolean isLongLessThenEqual = (value instanceof Long) && ((Long) value) <= Long.valueOf(operatorNum); + boolean isIntegerLessThenEqual = (value instanceof Integer) && ((Integer) value) <= Integer.valueOf(operatorNum); + boolean isShortLessThenEqual = (value instanceof Short) && ((Short) value) <= Short.valueOf(operatorNum); + boolean isFloatLessThenEqual = (value instanceof Float) && ((Float) value) <= Float.valueOf(operatorNum); + boolean isDoubleLessThenEqual = (value instanceof Double) && ((Double) value) <= Double.valueOf(operatorNum); + boolean isCollectionLessThenEqual = (value instanceof Collection) && ((Collection) value).size() <= Integer.valueOf(operatorNum); + if (isStringLessThenEqual || isLongLessThenEqual || isIntegerLessThenEqual || + isShortLessThenEqual || isFloatLessThenEqual || isDoubleLessThenEqual || isCollectionLessThenEqual) { + isLessThanEqual = Boolean.TRUE; + } + return isLessThanEqual; + } + + /** + * is not equal + * + * @param value field value + * @param operatorNum operatorNum + * @return is not equal + */ + private static Boolean isNotEqual(Object value, String operatorNum) { + Boolean isNotEqual = Boolean.FALSE; + if (value == null) { + return Boolean.FALSE; + } + boolean isStringNotEqual = (value instanceof String) && !value.equals(operatorNum); + boolean isLongNotEqual = (value instanceof Long) && !value.equals(Long.valueOf(operatorNum)); + boolean isIntegerNotEqual = (value instanceof Integer) && !value.equals(Integer.valueOf(operatorNum)); + boolean isShortNotEqual = (value instanceof Short) && !value.equals(Short.valueOf(operatorNum)); + boolean isFloatNotEqual = (value instanceof Float) && !value.equals(Float.valueOf(operatorNum)); + boolean isDoubleNotEqual = (value instanceof Double) && !value.equals(Double.valueOf(operatorNum)); + boolean isCollectionNotEqual = (value instanceof Collection) && ((Collection) value).size() != Integer.valueOf(operatorNum); + if (isStringNotEqual || isLongNotEqual || isIntegerNotEqual || + isShortNotEqual || isFloatNotEqual || isDoubleNotEqual || isCollectionNotEqual) { + isNotEqual = Boolean.TRUE; + } + return isNotEqual; + } + + /** + * is meets the parameter rules + * + * @param method method + * @param arguments arguments + * @return is meets + */ + private Boolean isCheck(Method method, Object[] arguments) { + Boolean isCheck = Boolean.TRUE; + if (!method.isAnnotationPresent(Check.class) || arguments == null) { + isCheck = Boolean.FALSE; + } + return isCheck; + } + + /** + * get the method + * + * @param joinPoint ProceedingJoinPoint + * @return method + */ + private Method getMethod(ProceedingJoinPoint joinPoint) { + MethodSignature signature = (MethodSignature) joinPoint.getSignature(); + Method method = signature.getMethod(); + if (method.getDeclaringClass().isInterface()) { + try { + method = joinPoint + .getTarget() + .getClass() + .getDeclaredMethod(joinPoint.getSignature().getName(), method.getParameterTypes()); + } catch (SecurityException | NoSuchMethodException e) { + LOG.error("" + e); + } + } + return method; + } + + /** + * file info + */ + class FieldInfo { + /** + * field + */ + String field; + /** + * prompt message + */ + String innerMsg; + /** + * operator + */ + String operator; + /** + * num of operator + */ + String operatorNum; + /** + * enum of operator + */ + Operator optEnum; + } + + /** + * enum of operator + */ + enum Operator { + /** + * spel expression + */ + SPEL("match spel expression", null), + /** + * GreaterThan + */ + GREATER_THAN(">", Checker::isGreaterThan), + /** + * GreaterThanEqual + */ + GREATER_THAN_EQUAL(">=", Checker::isGreaterThanEqual), + /** + * LessThan + */ + LESS_THAN("<", Checker::isLessThan), + /** + * LessThanEqual + */ + LESS_THAN_EQUAL("<=", Checker::isLessThanEqual), + /** + * NotEqual + */ + NOT_EQUAL("!=", Checker::isNotEqual), + /** + * NotNull + */ + NOT_NULL("not null", Checker::isNotNull); + + private String value; + private BiFunction fun; + + Operator(String value, BiFunction fun) { + this.value = value; + this.fun = fun; + } + } + +} From b0829bc5506990f6746838280f01d3ce7e98f747 Mon Sep 17 00:00:00 2001 From: cipher Date: 2020年6月30日 17:38:32 +0800 Subject: [PATCH 03/10] JHSDB --- .../java/com/cipher/jvm/JHSDB_TestCase.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 sandbox/src/main/java/com/cipher/jvm/JHSDB_TestCase.java diff --git a/sandbox/src/main/java/com/cipher/jvm/JHSDB_TestCase.java b/sandbox/src/main/java/com/cipher/jvm/JHSDB_TestCase.java new file mode 100644 index 0000000..f6512f6 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/jvm/JHSDB_TestCase.java @@ -0,0 +1,30 @@ +package com.cipher.jvm; + +/** + * staticObj, instanceObj, localObj 存放在哪里 + * -Xmx10m -XX:+UseSerialGC -XX:-UseCompressedOops + * + * @author: CipherCui + * @since 2020年6月30日 + */ +public class JHSDB_TestCase { + + static class Test { + static ObjectHolder staticObj = new ObjectHolder(); + ObjectHolder instanceObj = new ObjectHolder(); + + void foo() { + ObjectHolder localObj = new ObjectHolder(); + System.out.println("down"); // 这里设一个断点 + } + } + + private static class ObjectHolder { + } + + public static void main(String[] args) { + Test test = new JHSDB_TestCase.Test(); + test.foo(); + } + +} From bf7b84f32bfec329469791ad109df8d5cb293963 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: 2021年2月14日 12:05:47 +0800 Subject: [PATCH 04/10] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=BB=A7=E6=89=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/cipher/test/Base.java | 33 ++++++++++++++++++ .../src/main/java/com/cipher/test/Child.java | 28 +++++++++++++++ .../src/main/java/com/cipher/test/Foo.java | 24 ------------- .../src/main/java/com/cipher/test/Result.java | 24 ------------- .../src/main/java/com/cipher/test/Test.java | 34 +++++-------------- 5 files changed, 70 insertions(+), 73 deletions(-) create mode 100644 sandbox/src/main/java/com/cipher/test/Base.java create mode 100644 sandbox/src/main/java/com/cipher/test/Child.java delete mode 100644 sandbox/src/main/java/com/cipher/test/Foo.java delete mode 100644 sandbox/src/main/java/com/cipher/test/Result.java diff --git a/sandbox/src/main/java/com/cipher/test/Base.java b/sandbox/src/main/java/com/cipher/test/Base.java new file mode 100644 index 0000000..c8579c6 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/test/Base.java @@ -0,0 +1,33 @@ +package com.cipher.test; + +public class Base { + + public static int s; + private int a; + + static { + System.out.println("基类静态代码块, s: " + s); + s = 1; + } + + { + System.out.println("基类实例代码块,a: " + a); + a = 1; + } + + public Base() { + System.out.println("基类构造方法,a: " + a); + a = 2; + } + + protected void step() { + System.out.println("base s: " + s + ", a: " + a); + } + + public void action() { + System.out.println("start"); + step(); + System.out.println("end"); + } + +} diff --git a/sandbox/src/main/java/com/cipher/test/Child.java b/sandbox/src/main/java/com/cipher/test/Child.java new file mode 100644 index 0000000..9406d29 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/test/Child.java @@ -0,0 +1,28 @@ +package com.cipher.test; + +public class Child extends Base { + + public static int s; + private int a; + + static { + System.out.println("子类静态代码块, s: " + s); + s = 10; + } + + { + System.out.println("子类实例代码块,a: " + a); + a = 10; + } + + public Child() { + System.out.println("子类构造方法,a: " + a); + a = 20; + } + + @Override + protected void step() { + System.out.println("child s: " + s + ", a: " + a); + } + +} diff --git a/sandbox/src/main/java/com/cipher/test/Foo.java b/sandbox/src/main/java/com/cipher/test/Foo.java deleted file mode 100644 index d2c0f90..0000000 --- a/sandbox/src/main/java/com/cipher/test/Foo.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.cipher.test; - -public class Foo { - - private String name; - - private int age; - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getAge() { - return age; - } - - public void setAge(int age) { - this.age = age; - } -} diff --git a/sandbox/src/main/java/com/cipher/test/Result.java b/sandbox/src/main/java/com/cipher/test/Result.java deleted file mode 100644 index 3fbaa03..0000000 --- a/sandbox/src/main/java/com/cipher/test/Result.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.cipher.test; - -public class Result { - - private T model; - - private String code; - - public T getModel() { - return model; - } - - public void setModel(T model) { - this.model = model; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } -} diff --git a/sandbox/src/main/java/com/cipher/test/Test.java b/sandbox/src/main/java/com/cipher/test/Test.java index 3f83fc1..307a4fe 100644 --- a/sandbox/src/main/java/com/cipher/test/Test.java +++ b/sandbox/src/main/java/com/cipher/test/Test.java @@ -1,33 +1,17 @@ package com.cipher.test; -import net.jodah.typetools.TypeResolver; - -import java.util.function.Consumer; - public class Test { - public Foo getFoo() { - Foo foo = new Foo(); - foo.setAge(18); - foo.setName("cipher"); - return foo; - } - public static void main(String[] args) { - Test test = new Test(); - Result data = test.get((t) -> t.setName("aaa")); - System.out.println(); - } - - private Result get(Consumer consumer) { - Class aClass = TypeResolver.resolveRawArgument(Consumer.class, consumer.getClass()); - - return null; + System.out.println("---- new Child()"); + Child c = new Child(); + System.out.println("\n---- c.action()"); + c.action(); + Base b = c; + System.out.println("\n---- b.action()"); + b.action(); + System.out.println("\n---- b.s: " + b.s); + System.out.println("\n---- c.s: " + c.s); } - } - - - - From fe575cc25a485ba22fe291adde8802717ed59287 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: 2021年3月16日 21:00:10 +0800 Subject: [PATCH 05/10] =?UTF-8?q?redis=E7=AE=97=E6=B3=95java=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/cipher/javassist/Example.java | 4 +- .../src/main/java/com/cipher/jvm/Hello.java | 14 ++ .../java/com/cipher/redis_algorithm/readme.md | 1 + .../redis_algorithm/skiplist/Constant.java | 20 ++ .../cipher/redis_algorithm/skiplist/Test.java | 14 ++ .../redis_algorithm/skiplist/Zskiplist.java | 95 +++++++++ .../skiplist/ZskiplistNode.java | 121 ++++++++++++ .../redis_algorithm/skiplist/ZskiplistOp.java | 181 ++++++++++++++++++ .../src/main/java/com/cipher/test/Base.java | 33 ---- .../src/main/java/com/cipher/test/Child.java | 28 --- .../src/main/java/com/cipher/test/Test.java | 10 +- 11 files changed, 449 insertions(+), 72 deletions(-) create mode 100644 sandbox/src/main/java/com/cipher/jvm/Hello.java create mode 100644 sandbox/src/main/java/com/cipher/redis_algorithm/readme.md create mode 100644 sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Constant.java create mode 100644 sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Test.java create mode 100644 sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Zskiplist.java create mode 100644 sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistNode.java create mode 100644 sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistOp.java delete mode 100644 sandbox/src/main/java/com/cipher/test/Base.java delete mode 100644 sandbox/src/main/java/com/cipher/test/Child.java diff --git a/sandbox/src/main/java/com/cipher/javassist/Example.java b/sandbox/src/main/java/com/cipher/javassist/Example.java index e38523e..2c7d3c0 100644 --- a/sandbox/src/main/java/com/cipher/javassist/Example.java +++ b/sandbox/src/main/java/com/cipher/javassist/Example.java @@ -105,10 +105,10 @@ public static void test05() throws Exception { } public static void main(String[] args) throws Exception { -// test01(); + test01(); // test02(); // test03(); - test04(); +// test04(); // test05(); } diff --git a/sandbox/src/main/java/com/cipher/jvm/Hello.java b/sandbox/src/main/java/com/cipher/jvm/Hello.java new file mode 100644 index 0000000..5ee3beb --- /dev/null +++ b/sandbox/src/main/java/com/cipher/jvm/Hello.java @@ -0,0 +1,14 @@ +package com.cipher.jvm; + +/** + * 对比 class 字节码查看 + */ +public class Hello { + + private static String msg = "Goods morning"; + + public static void main(String[] args) { + System.out.println("msg = " + msg); + } + +} diff --git a/sandbox/src/main/java/com/cipher/redis_algorithm/readme.md b/sandbox/src/main/java/com/cipher/redis_algorithm/readme.md new file mode 100644 index 0000000..35d4216 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/redis_algorithm/readme.md @@ -0,0 +1 @@ +## redis算法java实现 \ No newline at end of file diff --git a/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Constant.java b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Constant.java new file mode 100644 index 0000000..0fedcd5 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Constant.java @@ -0,0 +1,20 @@ +package com.cipher.redis_algorithm.skiplist; + +/** + * 跳跃表用到的各种常量 + * + * @author cipher + */ +public class Constant { + + /** + * 节点层高最大值 + */ + public static final int ZSKIPLIST_MAXLEVEL = 64; + + /** + * 控制节点层高的概率,当 p=0.25 时,跳跃表的期望层高是 1/(1-0.25)≈1.33 + */ + public static final float ZSKIPLIST_P = 0.25f; + +} diff --git a/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Test.java b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Test.java new file mode 100644 index 0000000..95d2118 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Test.java @@ -0,0 +1,14 @@ +package com.cipher.redis_algorithm.skiplist; + +public class Test { + + public static void main(String[] args) { + Zskiplist zsl = Zskiplist.zslCreate(); + ZskiplistOp.zslInsert(zsl, 31, "C"); + ZskiplistOp.zslInsert(zsl, 41, "D"); + ZskiplistOp.zslInsert(zsl, 21, "B"); + ZskiplistOp.zslInsert(zsl, 1, "A"); + System.out.println(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Zskiplist.java b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Zskiplist.java new file mode 100644 index 0000000..376dc0a --- /dev/null +++ b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/Zskiplist.java @@ -0,0 +1,95 @@ +package com.cipher.redis_algorithm.skiplist; + +import static com.cipher.redis_algorithm.skiplist.Constant.ZSKIPLIST_MAXLEVEL; + +/** + * 跳跃表结构,用于管理节点 + * + * @author cipher + */ +public class Zskiplist { + + /** + * 指向跳跃表头节点, + * 头节点是一个特殊节点,它的 level 数组元素个数固定为 64。 + * 头节点的 ele 为空,score 为 0 + * 头节点不计入跳跃表的总长度 + */ + private ZskiplistNode header; + + /** + * 指向跳跃表尾节点,用于从后向前遍历 + */ + private ZskiplistNode tail; + + /** + * 跳跃表的长度,除头结点外,所有节点的个数 + */ + private int length; + + /** + * 跳跃表的高度,即跳跃表所有节点中层高最高的那个节点的层高 + */ + private int level; + + /** + * 创建跳跃表 + * + * @return 跳跃表结构 + */ + public static Zskiplist zslCreate() { + Zskiplist zsl = new Zskiplist(); + + // 跳跃表层高初始化为 1,长度初始化为 0 + zsl.level = 1; + zsl.length = 0; + + // 创建头节点,头节点不存储有序集合的 member 信息 + zsl.header = ZskiplistNode.zslCreateNode(ZSKIPLIST_MAXLEVEL, 0, null); + + // 头节点的 level 数组的每项 forward 都为 null,span 值都为 0 + for (int j = 0; j < ZSKIPLIST_MAXLEVEL; j++) { + zsl.header.getLevel()[j].setForward(null); + zsl.header.getLevel()[j].setSpan(0); + } + + // 头节点的后退指针为 null + zsl.header.setBackward(null); + + // 尾节点指向 null + zsl.tail = null; + return zsl; + } + + public ZskiplistNode getHeader() { + return header; + } + + public void setHeader(ZskiplistNode header) { + this.header = header; + } + + public ZskiplistNode getTail() { + return tail; + } + + public void setTail(ZskiplistNode tail) { + this.tail = tail; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public int getLevel() { + return level; + } + + public void setLevel(int level) { + this.level = level; + } +} diff --git a/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistNode.java b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistNode.java new file mode 100644 index 0000000..25be363 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistNode.java @@ -0,0 +1,121 @@ +package com.cipher.redis_algorithm.skiplist; + +/** + * 跳跃表节点 + * 跳跃表由多个节点构成,每个节点由多个层 {@link ZskiplistLevel} 构成 + * + * @author cipher + */ +public class ZskiplistNode { + + /** + * 用于存储字符串类型的数据, + * 即有序集合的 member 信息 + */ + private String ele; + + /** + * 用于存储排序的分值, + * 所有节点的分值是按从小到大排序的, + * 分值相同时,按 {@link ZskiplistNode#ele} 的字典序进行排序 + */ + private double score; + + /** + * 后退指针,只能指向当前节点最底层的前一个节点, + * 头节点和第一个节点的 backward 指向 null, + * 从后向前遍历跳跃表时使用 + */ + private ZskiplistNode backward; + + /** + * 用于存储当前节点的层,数组长度为 1~64 的随机值, + * 值越大概率越低 + */ + private ZskiplistLevel[] level; + + /** + * 创建跳跃表节点时,待创建节点的层高,分值,member 等都已确定 + * + * @param level 节点层高 + * @param score 分值 + * @param ele 元素值 + * @return 跳跃表节点 + */ + public static ZskiplistNode zslCreateNode(int level, double score, String ele) { + ZskiplistNode node = new ZskiplistNode(); + node.ele = ele; + node.score = score; + node.level = new ZskiplistLevel[level]; + for (int i = 0; i < node.level.length; i++) { + node.level[i] = new ZskiplistLevel(); + } + return node; + } + + public String getEle() { + return ele; + } + + public void setEle(String ele) { + this.ele = ele; + } + + public double getScore() { + return score; + } + + public void setScore(double score) { + this.score = score; + } + + public ZskiplistLevel[] getLevel() { + return level; + } + + public void setLevel(ZskiplistLevel[] level) { + this.level = level; + } + + public ZskiplistNode getBackward() { + return backward; + } + + public void setBackward(ZskiplistNode backward) { + this.backward = backward; + } + + /** + * 节点中的层 + */ + public static class ZskiplistLevel { + + /** + * 指向本层下一个节点,尾节点指向 null + */ + private ZskiplistNode forward; + + /** + * forward 指向节点与本节点之间的元素个数。 + * span 值越大,跳过的节点个数越多 + */ + private int span; + + public ZskiplistNode getForward() { + return forward; + } + + public void setForward(ZskiplistNode forward) { + this.forward = forward; + } + + public int getSpan() { + return span; + } + + public void setSpan(int span) { + this.span = span; + } + } + +} diff --git a/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistOp.java b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistOp.java new file mode 100644 index 0000000..6c908cc --- /dev/null +++ b/sandbox/src/main/java/com/cipher/redis_algorithm/skiplist/ZskiplistOp.java @@ -0,0 +1,181 @@ +package com.cipher.redis_algorithm.skiplist; + +import java.math.BigDecimal; +import java.util.Random; + +import static com.cipher.redis_algorithm.skiplist.Constant.ZSKIPLIST_MAXLEVEL; +import static com.cipher.redis_algorithm.skiplist.Constant.ZSKIPLIST_P; +import static com.cipher.redis_algorithm.skiplist.ZskiplistNode.zslCreateNode; + +/** + * 跳跃表操作 + * + * @author cipher + */ +public class ZskiplistOp { + + /** + * 插入节点,共需要 4 个 步骤: + * 1 收集需要更新的节点与步长信息; + * 2 获取随机层高,补全需要更新的节点 + * 3 创建并分层插入节点,同时更新同层前一节点步长信息; + * 4 更新新增节点未涉及层节点的步长信息,以及调整 backward + * + * @param zsl 跳跃表结构 + * @param score 待插入节点的分值 + * @param ele 待插入节点的元素 + * @return 跳跃表的头节点 + */ + public static ZskiplistNode zslInsert(Zskiplist zsl, double score, String ele) { + + // 插入节点时,需要更新被插入节点每层的前一个节点。由于每层更新的节点不一样, + // 所以将插入新增节点后每层受影响节点存在 update 数组中,update[i]为第 i + 1 层会受影响节点 + ZskiplistNode[] update = new ZskiplistNode[ZSKIPLIST_MAXLEVEL]; + + // 将每层头节点与会受影响的节点中间存在节点数存在 rank 数组中,rank[i] 为头节点与第 i + 1 层会受影响节点中间存在的节点数, + // 在更新 update[i] 的 span 和设置新插入节点的 span 时用到 + Integer[] rank = new Integer[ZSKIPLIST_MAXLEVEL]; + + // 第一步,收集需要更新的节点与步长信息 + ZskiplistNode x = zsl.getHeader(); + // 从最高层开始向下一层一层地遍历 + for (int i = zsl.getLevel() - 1; i>= 0; i--) { + + // 第一次 for 循环的遍历,即 i==zsl.getLevel()-1 时步长从 0 开始计算, + // 后序遍历的步长需要在上一层的基础上开始计算,因此 rank[i] 初始为 rank[i+1] + rank[i] = i == (zsl.getLevel() - 1) ? 0 : rank[i + 1]; + + // 这里 white 循环是同一层中的节点遍历,为了找到本层中新插入节点的前一个节点, + // 需要满足以下条件: + // 1、本层指向的下一个节点不为空; + // 2、本层指向的下一个节点的分值小于新插入节点的分值,分值相同时用元素值来比较 + while (x.getLevel()[i].getForward() != null && + (x.getLevel()[i].getForward().getScore() < score || + (x.getLevel()[i].getForward().getScore() == score && + x.getLevel()[i].getForward().getEle().compareTo(ele) < 0))) { + // 步长累加 + rank[i] += x.getLevel()[i].getSpan(); + // x 移动到下一个节点 + x = x.getLevel()[i].getForward(); + } + + // 记录本层中需要修改的节点,即新插入节点的前一个节点 + update[i] = x; + } + + // 第二步,获取随机层高,补全需要更新的节点 + // 获取随机层高 + int level = zslRandomLevel(); + // 如果新插入节点的层高大于跳跃表的原高度,那么高出的这几层的头节点也是需要更新信息的 + if (level> zsl.getLevel()) { + // 从高出的层数开始向上遍历 + for (int i = zsl.getLevel(); i < level; i++) { + + // 因为是高出的层,所以只有头节点需要更新,步长自然为 0 + rank[i] = 0; + update[i] = zsl.getHeader(); + + // 先将 span 值赋值为跳跃表的总长度,方便后序计算 + // 注意这时的 span 不是最终值,在插入节点后会重新计算赋值 + update[i].getLevel()[i].setSpan(zsl.getLength()); + } + // 因为新插入节点的层高大于跳跃表的原高度,所以更新跳跃表的高度 + zsl.setLevel(level); + } + + // 第三步,创建并分层插入节点,同时更新同层前一节点步长信息 + ZskiplistNode newNode = zslCreateNode(level, score, ele); + // 从第 0 层开始,向上一层一层地遍历 + for (int i = 0; i < level; i++) { + + // 本层中插入节点 + // 相当于链表的插入操作, A -> B 更新为 A -> newNode -> B + newNode.getLevel()[i].setForward(update[i].getLevel()[i].getForward()); + update[i].getLevel()[i].setForward(newNode); + + /** + * 说明: + * 步长的赋值操作有点难懂,稍微解释一下,因为跳跃表的每个节点都至少有一层(这是由 zslRandomLevel() 方法保证的), + * 因此跳跃表的第一层是一个普通链表,一个节点挨着一个节点,没有跨过任何节点。 + * update[0] 表示第一层需要修改的节点,这个节点必定为第一层中紧挨着新插入节点的前一个节点, + * rank[0] 就是紧挨着新插入节点的前一个节点到头节点的距离。 + */ + + // 设置新增节点步长信息 + // 因为 rank[0] 表示紧挨着新插入节点的前一个节点到头节点的距离(见上面的说明), + // 所以 (rank[0] - rank[i]) 表示 update[i] 节点到紧挨着新插入节点的前一个节点的距离, + // update[i] 的 span 值表示原跳跃表中 update[i] 到下一节点的距离, + // 这是 update[i] 和 update[i] 的下一节点之间要插入新增的节点,update[i] -> next 更新为 update[i] -> newNode -> next + // 所以新增节点到下一节点的距离为 update[i].span - (rank[0] - rank[i]) + newNode.getLevel()[i].setSpan(update[i].getLevel()[i].getSpan() - ((rank[0] - rank[i]))); + + // 更新本层中新插入节点的前一个节点,即 update[i] 的步长信息, + // 因为 rank[0] 表示紧挨着新插入节点的前一个节点到头节点的距离(见上面的说明), + // 所以 (rank[0] - rank[i]) 表示 update[i] 节点到紧挨着新插入节点的前一个节点的距离, + // 因此这个距离加 1 就是 update[i] 节点到新插入节点的距离 + /** + * rank[i] (rank[0]-rank[i]) + * / \ / \ + * Li: head -----------> A ------------ + * . + * . rank[0] + * . / \ 1 + * . / \ / \ + * L0: head -----------> A ------------> B -----> newNode + */ + update[i].getLevel()[i].setSpan((rank[0] - rank[i]) + 1); + } + + // 更新新增节点未涉及层节点的步长信息,以及调整 backward + // 能进入此循环,表示新插入节点的层高小于跳跃表原高度, + // 那么高于新插入节点层高的那些需要更新的节点,步长需要加 1 (因为在它和它的下一个节点之间插入了新增节点) + for (int i = level; i < zsl.getLevel(); i++) { + int span = update[i].getLevel()[i].getSpan(); + update[i].getLevel()[i].setSpan(span + 1); + } + + // 调整 backward + // update[0] 表示紧挨着新插入节点的前一个节点,每个节点的后退指针只有一个,与层数无关 + // 所以新插入节点的后退指针指向 update[0],如果 update[0] 是头节点,则指向 null + newNode.setBackward((update[0] == zsl.getHeader()) ? null : update[0]); + // 如果新插入节点的下一个节点不是空,表示新插入节点不是最后一个节点, + // 那么需要更新新插入节点的下一个节点的后退指针,指向新插入节点 + if (newNode.getLevel()[0].getForward() != null) { + newNode.getLevel()[0].getForward().setBackward(newNode); + } + // 如果新插入节点是最后一个节点,则需要更新跳跃表的尾节点为新插入节点 + else { + zsl.setTail(newNode); + } + // 插入节点后,跳跃表的长度加 1 + zsl.setLength(zsl.getLength() + 1); + return newNode; + } + + /** + * Redis 通过此函数随机生成一个 1~64 的值,作为新建节点的高度, + * 值越大出现的概率越低,节点层高确定之后便不会再修改 + * + * @return 层高 + */ + public static int zslRandomLevel() { + int level = 1; + Random random = new Random(); + while (round(random.nextFloat()) < ZSKIPLIST_P) { + level += 1; + } + return Math.min(level, ZSKIPLIST_MAXLEVEL); + } + + /** + * 保留小数点两位 + * 注意:redis 中是使用位运算来比较大小,这里为了便于理解,改成直接比较小数 + * + * @param num 原值 + * @return 保留小数点两位后的值 + */ + private static float round(float num) { + return new BigDecimal(num).setScale(2, BigDecimal.ROUND_HALF_UP).floatValue(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/test/Base.java b/sandbox/src/main/java/com/cipher/test/Base.java deleted file mode 100644 index c8579c6..0000000 --- a/sandbox/src/main/java/com/cipher/test/Base.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.cipher.test; - -public class Base { - - public static int s; - private int a; - - static { - System.out.println("基类静态代码块, s: " + s); - s = 1; - } - - { - System.out.println("基类实例代码块,a: " + a); - a = 1; - } - - public Base() { - System.out.println("基类构造方法,a: " + a); - a = 2; - } - - protected void step() { - System.out.println("base s: " + s + ", a: " + a); - } - - public void action() { - System.out.println("start"); - step(); - System.out.println("end"); - } - -} diff --git a/sandbox/src/main/java/com/cipher/test/Child.java b/sandbox/src/main/java/com/cipher/test/Child.java deleted file mode 100644 index 9406d29..0000000 --- a/sandbox/src/main/java/com/cipher/test/Child.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.cipher.test; - -public class Child extends Base { - - public static int s; - private int a; - - static { - System.out.println("子类静态代码块, s: " + s); - s = 10; - } - - { - System.out.println("子类实例代码块,a: " + a); - a = 10; - } - - public Child() { - System.out.println("子类构造方法,a: " + a); - a = 20; - } - - @Override - protected void step() { - System.out.println("child s: " + s + ", a: " + a); - } - -} diff --git a/sandbox/src/main/java/com/cipher/test/Test.java b/sandbox/src/main/java/com/cipher/test/Test.java index 307a4fe..d6d1c6e 100644 --- a/sandbox/src/main/java/com/cipher/test/Test.java +++ b/sandbox/src/main/java/com/cipher/test/Test.java @@ -3,15 +3,7 @@ public class Test { public static void main(String[] args) { - System.out.println("---- new Child()"); - Child c = new Child(); - System.out.println("\n---- c.action()"); - c.action(); - Base b = c; - System.out.println("\n---- b.action()"); - b.action(); - System.out.println("\n---- b.s: " + b.s); - System.out.println("\n---- c.s: " + c.s); + System.out.println("Hello, World!"); } } From 7138bcb427345cad166a1980790c0cdf3a9105b8 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: 2021年10月26日 16:57:55 +0800 Subject: [PATCH 06/10] add some file --- sandbox/pom.xml | 13 +++ .../E_Binary_Search_Tree/BST.java | 92 +++++++++++++++---- .../FileOperation.java | 0 .../map/BSTMap.java | 0 .../map/LeetCode349.java | 0 .../map/LeetCode350.java | 0 .../map/LinkedListMap.java | 0 .../map/Main.java | 0 .../map/Map.java | 0 .../resource/a-tale-of-two-cities.txt | 0 .../resource/pride-and-prejudice.txt | 0 .../set/BSTSet.java | 0 .../set/LeetCode804.java | 0 .../set/LinkedListSet.java | 0 .../set/Main.java | 0 .../set/Set.java | 0 .../src/main/java/com/cipher/test/Test.java | 24 ++++- 17 files changed, 108 insertions(+), 21 deletions(-) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/FileOperation.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/map/BSTMap.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/map/LeetCode349.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/map/LeetCode350.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/map/LinkedListMap.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/map/Main.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/map/Map.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/resource/a-tale-of-two-cities.txt (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/resource/pride-and-prejudice.txt (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/set/BSTSet.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/set/LeetCode804.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/set/LinkedListSet.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/set/Main.java (100%) rename sandbox/src/main/java/com/cipher/data_structure/{F_Set_And_Map => F_Set_and_Map}/set/Set.java (100%) diff --git a/sandbox/pom.xml b/sandbox/pom.xml index f0f4c1c..047aa04 100644 --- a/sandbox/pom.xml +++ b/sandbox/pom.xml @@ -113,6 +113,19 @@ 1.7.4 + + org.openjdk.jmh + jmh-core + 1.19 + + + org.openjdk.jmh + jmh-generator-annprocess + 1.19 + provided + + + diff --git a/sandbox/src/main/java/com/cipher/data_structure/E_Binary_Search_Tree/BST.java b/sandbox/src/main/java/com/cipher/data_structure/E_Binary_Search_Tree/BST.java index 922421d..b42fb04 100644 --- a/sandbox/src/main/java/com/cipher/data_structure/E_Binary_Search_Tree/BST.java +++ b/sandbox/src/main/java/com/cipher/data_structure/E_Binary_Search_Tree/BST.java @@ -93,23 +93,6 @@ private void postOrder(Node node) { } } - public void preOrderNR() { - if (root != null) { - Stack stack = new Stack(); - stack.push(root); - while (!stack.isEmpty()) { - Node cur = stack.pop(); - System.out.println(cur.e); - if (cur.right != null) { - stack.push(cur.right); - } - if (cur.left != null) { - stack.push(cur.left); - } - } - } - } - public void levelOrder() { if (root != null) { Queue queue = new LinkedList(); @@ -234,14 +217,85 @@ public Node(E e) { } } + public void inOrderNR() { + if (root != null) { + Stack stack = new Stack(); + while (!stack.isEmpty() || root != null) { + if (root != null) { + stack.push(root); + root = root.left; + } else { + Node curr = stack.pop(); + System.out.println(curr.e); + root = curr.right; + } + } + } + } + + public void preOrderNR() { + if (root != null) { + Stack stack = new Stack(); + while (!stack.isEmpty() || root != null) { + if (root != null) { + System.out.println(root.e); + stack.push(root); + root = root.left; + } else { + Node curr = stack.pop(); + root = curr.right; + } + } + } + } + + public void postOrderNR2() { + Node cur = root; + Stack stack = new Stack(); + stack.push(cur); + while (!stack.isEmpty()) { + Node peek = stack.peek(); + if (peek.left != null && peek.left != cur && peek.right != cur) { + stack.push(peek.left); + } else if (peek.right != null && peek.right != cur) { + stack.push((peek.right)); + } else { + Node temp = stack.pop(); + System.out.println(temp.e); + cur = temp; + } + } + } + + public void postOrderNR() { + LinkedList list = new LinkedList(); + if (root != null) { + Stack stack = new Stack(); + while (!stack.isEmpty() || root != null) { + if (root != null) { + list.addFirst(root.e); + stack.push(root); + root = root.right; + } else { + Node curr = stack.pop(); + root = curr.left; + } + } + } + for (E e : list) { + System.out.println(e); + } + } + public static void main(String[] args) { BST bst = new BST(); int[] nums = {5, 3, 6, 2, 4, 8}; for (Integer i : nums) { bst.add(i); } - bst.remove(6); - bst.levelOrder(); +// bst.inOrderNR(); +// bst.preOrderNR(); + bst.preOrderNR(); } } diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/FileOperation.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/FileOperation.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/FileOperation.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/FileOperation.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/BSTMap.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/BSTMap.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/BSTMap.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/BSTMap.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/LeetCode349.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/LeetCode349.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/LeetCode349.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/LeetCode349.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/LeetCode350.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/LeetCode350.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/LeetCode350.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/LeetCode350.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/LinkedListMap.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/LinkedListMap.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/LinkedListMap.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/LinkedListMap.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/Main.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/Main.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/Main.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/Main.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/Map.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/Map.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/map/Map.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/map/Map.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/resource/a-tale-of-two-cities.txt b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/resource/a-tale-of-two-cities.txt similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/resource/a-tale-of-two-cities.txt rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/resource/a-tale-of-two-cities.txt diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/resource/pride-and-prejudice.txt b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/resource/pride-and-prejudice.txt similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/resource/pride-and-prejudice.txt rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/resource/pride-and-prejudice.txt diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/BSTSet.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/BSTSet.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/BSTSet.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/BSTSet.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/LeetCode804.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/LeetCode804.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/LeetCode804.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/LeetCode804.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/LinkedListSet.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/LinkedListSet.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/LinkedListSet.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/LinkedListSet.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/Main.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/Main.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/Main.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/Main.java diff --git a/sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/Set.java b/sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/Set.java similarity index 100% rename from sandbox/src/main/java/com/cipher/data_structure/F_Set_And_Map/set/Set.java rename to sandbox/src/main/java/com/cipher/data_structure/F_Set_and_Map/set/Set.java diff --git a/sandbox/src/main/java/com/cipher/test/Test.java b/sandbox/src/main/java/com/cipher/test/Test.java index d6d1c6e..a0aa7b8 100644 --- a/sandbox/src/main/java/com/cipher/test/Test.java +++ b/sandbox/src/main/java/com/cipher/test/Test.java @@ -2,8 +2,28 @@ public class Test { - public static void main(String[] args) { - System.out.println("Hello, World!"); + public static void main(String[] args) throws Exception { + StopThread thread = new StopThread(); + thread.start(); + Thread.sleep(2000); + thread.interrupt(); + System.out.println("stop"); + } + + private static class StopThread extends Thread { + + @Override + public void run() { + while (!Thread.currentThread().isInterrupted()) { + System.out.println("aaa"); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + } } From 64c131af6464a8a6d80464535e7f811d918462a9 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: 2021年10月26日 17:00:23 +0800 Subject: [PATCH 07/10] add some file --- .../src/main/java/com/cipher/jmh/Test.java | 47 ++++++++++++ .../com/cipher/test/NonReentrantLock.java | 74 +++++++++++++++++++ .../main/java/com/cipher/test/Solution.java | 34 +++++++++ 3 files changed, 155 insertions(+) create mode 100644 sandbox/src/main/java/com/cipher/jmh/Test.java create mode 100644 sandbox/src/main/java/com/cipher/test/NonReentrantLock.java create mode 100644 sandbox/src/main/java/com/cipher/test/Solution.java diff --git a/sandbox/src/main/java/com/cipher/jmh/Test.java b/sandbox/src/main/java/com/cipher/jmh/Test.java new file mode 100644 index 0000000..533e138 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/jmh/Test.java @@ -0,0 +1,47 @@ +package com.cipher.jmh; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Fork(1) +@Warmup(iterations = 1) +@Measurement(iterations = 5) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Threads(1) +@State(Scope.Benchmark) +public class Test { + + private Map hashMap; + private Map synchronizedMap; + + @Setup + public void setUp() { + this.hashMap = new HashMap(); + this.synchronizedMap = Collections.synchronizedMap(new HashMap()); + } + + @Benchmark + public void testHashMap() { + this.hashMap.put(System.nanoTime(), System.nanoTime()); + } + + @Benchmark + public void testSynchronizedMap() { + this.synchronizedMap.put(System.nanoTime(), System.nanoTime()); + } + + public static void main(String[] args) throws RunnerException { + final Options opts = new OptionsBuilder().include(Test.class.getSimpleName()).build(); + new Runner(opts).run(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/test/NonReentrantLock.java b/sandbox/src/main/java/com/cipher/test/NonReentrantLock.java new file mode 100644 index 0000000..1843b4a --- /dev/null +++ b/sandbox/src/main/java/com/cipher/test/NonReentrantLock.java @@ -0,0 +1,74 @@ +package com.cipher.test; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; + +public class NonReentrantLock implements Lock { + + private static class Sync extends AbstractQueuedSynchronizer { + @Override + protected boolean isHeldExclusively() { + return getState() == 1; + } + + @Override + protected boolean tryAcquire(int acquires) { + assert acquires == 1; + if (compareAndSetState(0, 1)) { + setExclusiveOwnerThread(Thread.currentThread()); + return true; + } + return false; + } + + @Override + protected boolean tryRelease(int releases) { + assert releases == 1; + if (getState() == 0) { + throw new IllegalMonitorStateException(); + } + setExclusiveOwnerThread(null); + setState(0); + return true; + } + + Condition newCondition() { + return new ConditionObject(); + } + } + + private final Sync sync = new Sync(); + + @Override + public void lock() { + sync.acquire(1); + } + + @Override + public void lockInterruptibly() throws InterruptedException { + sync.acquireInterruptibly(1); + } + + @Override + public boolean tryLock() { + return sync.tryAcquire(1); + } + + @Override + public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + return sync.tryAcquireNanos(1, unit.toNanos(time)); + } + + @Override + public void unlock() { + sync.release(1); + } + + @Override + public Condition newCondition() { + return sync.newCondition(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/test/Solution.java b/sandbox/src/main/java/com/cipher/test/Solution.java new file mode 100644 index 0000000..eaf3966 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/test/Solution.java @@ -0,0 +1,34 @@ +package com.cipher.test; + +import java.util.LinkedList; + +class Solution { + + public String minWindow(String s, String t) { + int m = s.length(); + int n = t.length(); + int[] hash = new int[128]; + for (char c : t.toCharArray()) { + hash[c]--; + } + String res = ""; + for (int i = 0, j = 0, cnt = 0; i < m; i++) { + hash[s.charAt(i)]++; + if (hash[s.charAt(i)] <= 0) { + cnt++; + } + while (cnt == n && hash[s.charAt(j)]> 0) { + hash[s.charAt(j++)]--; + } + if (cnt == n && ("".equals(res) || res.length()> i - j + 1)) { + res = s.substring(j, i + 1); + } + } + return res; + } + + public static void main(String[] args) { + String res = new Solution().minWindow("ADOBECODEBANC", "ABC"); + System.out.println(); + } +} From 4d956101df43f0a366c914801f33536ce4c1db76 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: Wed, 9 Mar 2022 16:19:11 +0800 Subject: [PATCH 08/10] add some file --- sandbox/pom.xml | 1 - .../collection/RandomStringGenerator.java | 16 ++++ .../main/java/com/cipher/test/Solution.java | 80 ++++++++++++++----- 3 files changed, 77 insertions(+), 20 deletions(-) create mode 100644 sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java diff --git a/sandbox/pom.xml b/sandbox/pom.xml index 047aa04..963d972 100644 --- a/sandbox/pom.xml +++ b/sandbox/pom.xml @@ -125,7 +125,6 @@ provided - diff --git a/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java b/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java new file mode 100644 index 0000000..6f83239 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java @@ -0,0 +1,16 @@ +package com.cipher.interview.collection; + +import java.util.Iterator; + +/** + * @author cipher + */ +public class RandomStringGenerator implements Iterable { + + + @Override + public Iterator iterator() { + return null; + } + +} diff --git a/sandbox/src/main/java/com/cipher/test/Solution.java b/sandbox/src/main/java/com/cipher/test/Solution.java index eaf3966..0a40c37 100644 --- a/sandbox/src/main/java/com/cipher/test/Solution.java +++ b/sandbox/src/main/java/com/cipher/test/Solution.java @@ -1,34 +1,76 @@ package com.cipher.test; -import java.util.LinkedList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; class Solution { + Map areaMap = new HashMap(); + int[][] dirs = new int[][]{{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; - public String minWindow(String s, String t) { - int m = s.length(); - int n = t.length(); - int[] hash = new int[128]; - for (char c : t.toCharArray()) { - hash[c]--; - } - String res = ""; - for (int i = 0, j = 0, cnt = 0; i < m; i++) { - hash[s.charAt(i)]++; - if (hash[s.charAt(i)] <= 0) { - cnt++; + private boolean inArea(int[][] grid, int i, int j) { + return i>= 0 && i < grid.length && j>= 0 && j < grid[0].length; + } + + public int largestIsland(int[][] grid) { + int res = 0; + int index = 2; + boolean hasIsland = false; + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + areaMap.put(index, curArea(grid, i, j, index)); + index++; + hasIsland = true; + } } - while (cnt == n && hash[s.charAt(j)]> 0) { - hash[s.charAt(j++)]--; + } + if (!hasIsland) { + return 1; + } + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 0) { + res = Math.max(res, newArea(grid, i, j)); + } } - if (cnt == n && ("".equals(res) || res.length()> i - j + 1)) { - res = s.substring(j, i + 1); + } + return res; + } + + private int curArea(int[][] grid, int i, int j, int index) { + if (!inArea(grid, i, j)) { + return 0; + } + if (grid[i][j] != 1) { + return 0; + } + grid[i][j] = index; + int res = 1; + for (int[] dir : dirs) { + res += curArea(grid, i + dir[0], j + dir[1], index); + } + return res; + } + + private int newArea(int[][] grid, int i, int j) { + Set set = new HashSet(); + int res = 1; + for (int[] dir : dirs) { + int ti = i + dir[0]; + int tj = j + dir[1]; + if (inArea(grid, ti, tj) && grid[ti][tj] != 0 && !set.contains(grid[ti][tj])) { + res += areaMap.get(grid[ti][tj]); + set.add(grid[ti][tj]); } } return res; } public static void main(String[] args) { - String res = new Solution().minWindow("ADOBECODEBANC", "ABC"); + Solution solution = new Solution(); + int i = solution.largestIsland(new int[][]{{1, 1}, {1, 1}}); System.out.println(); } -} +} \ No newline at end of file From 3eaa7789d9b3b7f56c4a0a4b8f59fee9d454cee1 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: 2022年3月14日 19:30:18 +0800 Subject: [PATCH 09/10] add some file --- sandbox/pom.xml | 6 +++++ .../collection/RandomStringGenerator.java | 27 ++++++++++++++++++- .../proxy/dynamic/cglib/CarLogProxy.java | 1 + .../src/main/java/com/cipher/test/Test.java | 21 --------------- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/sandbox/pom.xml b/sandbox/pom.xml index 963d972..6a24467 100644 --- a/sandbox/pom.xml +++ b/sandbox/pom.xml @@ -124,6 +124,12 @@ 1.19 provided + + junit + junit + 4.13 + compile + diff --git a/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java b/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java index 6f83239..59028d3 100644 --- a/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java +++ b/sandbox/src/main/java/com/cipher/interview/collection/RandomStringGenerator.java @@ -1,16 +1,41 @@ package com.cipher.interview.collection; +import java.util.Arrays; import java.util.Iterator; +import java.util.List; /** * @author cipher */ public class RandomStringGenerator implements Iterable { + private final List list; + + public RandomStringGenerator(List list) { + this.list = list; + } @Override public Iterator iterator() { - return null; + return new Iterator() { + @Override + public boolean hasNext() { + return true; + } + + @Override + public T next() { + return list.get((int) (list.size() * Math.random())); + } + }; + } + + public static void main(String[] args) { + List list = Arrays.asList("List", "Tree", "Array"); + RandomStringGenerator gen = new RandomStringGenerator(list); + for (String s : gen) { + System.out.println(s); + } } } diff --git a/sandbox/src/main/java/com/cipher/pattern/proxy/dynamic/cglib/CarLogProxy.java b/sandbox/src/main/java/com/cipher/pattern/proxy/dynamic/cglib/CarLogProxy.java index 06d9cfe..1252704 100644 --- a/sandbox/src/main/java/com/cipher/pattern/proxy/dynamic/cglib/CarLogProxy.java +++ b/sandbox/src/main/java/com/cipher/pattern/proxy/dynamic/cglib/CarLogProxy.java @@ -31,6 +31,7 @@ public Object getProxy(Class clazz) { * @return * @throws Throwable */ + @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("日志开始......"); // 代理类调用父类的方法 diff --git a/sandbox/src/main/java/com/cipher/test/Test.java b/sandbox/src/main/java/com/cipher/test/Test.java index a0aa7b8..2f24dcd 100644 --- a/sandbox/src/main/java/com/cipher/test/Test.java +++ b/sandbox/src/main/java/com/cipher/test/Test.java @@ -3,27 +3,6 @@ public class Test { public static void main(String[] args) throws Exception { - StopThread thread = new StopThread(); - thread.start(); - Thread.sleep(2000); - thread.interrupt(); - System.out.println("stop"); - } - - private static class StopThread extends Thread { - - @Override - public void run() { - while (!Thread.currentThread().isInterrupted()) { - System.out.println("aaa"); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - } } From fabffbbfd3c0093ba9717c3f94fc30f646f8b417 Mon Sep 17 00:00:00 2001 From: ciphermagic Date: 2022年3月15日 14:45:19 +0800 Subject: [PATCH 10/10] add some file --- .../cipher/interview/annotation/Aspect.java | 17 +++ .../cipher/interview/annotation/IAspect.java | 11 ++ .../cipher/interview/annotation/IOrder.java | 9 ++ .../interview/annotation/ObjectFactory.java | 45 +++++++ .../cipher/interview/annotation/Order.java | 33 +++++ .../interview/annotation/TimeUsageAspect.java | 17 +++ .../interview/buffer/BufferExampleTest.java | 69 ++++++++++ .../interview/buffer/WordCountTest.java | 122 ++++++++++++++++++ .../com/cipher/interview/proxy/Aspect.java | 63 +++++++++ .../com/cipher/interview/proxy/IOrder.java | 9 ++ .../com/cipher/interview/proxy/Order.java | 21 +++ .../interview/proxy/ProxyExampleTest.java | 19 +++ .../interview/proxy/TimeUsageAspect.java | 21 +++ .../com/cipher/interview/stream/Event.java | 60 +++++++++ 14 files changed, 516 insertions(+) create mode 100644 sandbox/src/main/java/com/cipher/interview/annotation/Aspect.java create mode 100644 sandbox/src/main/java/com/cipher/interview/annotation/IAspect.java create mode 100644 sandbox/src/main/java/com/cipher/interview/annotation/IOrder.java create mode 100644 sandbox/src/main/java/com/cipher/interview/annotation/ObjectFactory.java create mode 100644 sandbox/src/main/java/com/cipher/interview/annotation/Order.java create mode 100644 sandbox/src/main/java/com/cipher/interview/annotation/TimeUsageAspect.java create mode 100644 sandbox/src/main/java/com/cipher/interview/buffer/BufferExampleTest.java create mode 100644 sandbox/src/main/java/com/cipher/interview/buffer/WordCountTest.java create mode 100644 sandbox/src/main/java/com/cipher/interview/proxy/Aspect.java create mode 100644 sandbox/src/main/java/com/cipher/interview/proxy/IOrder.java create mode 100644 sandbox/src/main/java/com/cipher/interview/proxy/Order.java create mode 100644 sandbox/src/main/java/com/cipher/interview/proxy/ProxyExampleTest.java create mode 100644 sandbox/src/main/java/com/cipher/interview/proxy/TimeUsageAspect.java create mode 100644 sandbox/src/main/java/com/cipher/interview/stream/Event.java diff --git a/sandbox/src/main/java/com/cipher/interview/annotation/Aspect.java b/sandbox/src/main/java/com/cipher/interview/annotation/Aspect.java new file mode 100644 index 0000000..5843caf --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/annotation/Aspect.java @@ -0,0 +1,17 @@ +package com.cipher.interview.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author cipher + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Aspect { + + Class type(); + +} diff --git a/sandbox/src/main/java/com/cipher/interview/annotation/IAspect.java b/sandbox/src/main/java/com/cipher/interview/annotation/IAspect.java new file mode 100644 index 0000000..b7e3124 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/annotation/IAspect.java @@ -0,0 +1,11 @@ +package com.cipher.interview.annotation; + +/** + * @author cipher + */ +public interface IAspect { + + void before(); + void after(); + +} diff --git a/sandbox/src/main/java/com/cipher/interview/annotation/IOrder.java b/sandbox/src/main/java/com/cipher/interview/annotation/IOrder.java new file mode 100644 index 0000000..5168032 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/annotation/IOrder.java @@ -0,0 +1,9 @@ +package com.cipher.interview.annotation; + +public interface IOrder { + + void pay() throws InterruptedException; + + void show(); + +} diff --git a/sandbox/src/main/java/com/cipher/interview/annotation/ObjectFactory.java b/sandbox/src/main/java/com/cipher/interview/annotation/ObjectFactory.java new file mode 100644 index 0000000..48e7600 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/annotation/ObjectFactory.java @@ -0,0 +1,45 @@ +package com.cipher.interview.annotation; + +import org.junit.Test; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Proxy; +import java.util.LinkedList; + +/** + * @author cipher + */ +@SuppressWarnings("unchecked") +public class ObjectFactory { + + public static T newInstance(Class clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { + + Annotation[] annotations = clazz.getAnnotations(); + LinkedList aspects = new LinkedList(); + + for (Annotation annotation : annotations) { + if (annotation instanceof Aspect) { + Class type = ((Aspect) annotation).type(); + IAspect aspect = (IAspect) (type.getConstructor().newInstance()); + aspects.push(aspect); + } + } + + T inst = clazz.getConstructor().newInstance(); + return (T) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), (proxy, method, args) -> { + aspects.forEach(IAspect::before); + Object result = method.invoke(inst); + aspects.forEach(IAspect::after); + return result; + }); + } + + @Test + public void test() throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, InterruptedException { + IOrder order = ObjectFactory.newInstance(Order.class); + order.pay(); + order.show(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/annotation/Order.java b/sandbox/src/main/java/com/cipher/interview/annotation/Order.java new file mode 100644 index 0000000..aa15965 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/annotation/Order.java @@ -0,0 +1,33 @@ +package com.cipher.interview.annotation; + +import org.junit.Test; + +import java.lang.reflect.Proxy; + +@Aspect(type = TimeUsageAspect.class) +public class Order implements IOrder { + + int state = 0; + + @Override + public void pay() throws InterruptedException { + Thread.sleep(50); + this.state = 1; + } + + @Override + public void show() { + System.out.println("order status:" + this.state); + } + + @Test + public void testProxy() throws InterruptedException { + IOrder order = new Order(); + IOrder proxy = (IOrder) Proxy.newProxyInstance(Order.class.getClassLoader(), new Class[]{IOrder.class}, (proxy1, method, args) -> { + System.out.println("before invoke method:" + method); + return method.invoke(order); + }); + proxy.pay(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/annotation/TimeUsageAspect.java b/sandbox/src/main/java/com/cipher/interview/annotation/TimeUsageAspect.java new file mode 100644 index 0000000..1f191d8 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/annotation/TimeUsageAspect.java @@ -0,0 +1,17 @@ +package com.cipher.interview.annotation; + +public class TimeUsageAspect implements IAspect { + + long start; + + @Override + public void before() { + start = System.currentTimeMillis(); + } + + @Override + public void after() { + long usage = System.currentTimeMillis() - start; + System.out.format("time usage : %dms\n", usage); + } +} diff --git a/sandbox/src/main/java/com/cipher/interview/buffer/BufferExampleTest.java b/sandbox/src/main/java/com/cipher/interview/buffer/BufferExampleTest.java new file mode 100644 index 0000000..23aac25 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/buffer/BufferExampleTest.java @@ -0,0 +1,69 @@ +package com.cipher.interview.buffer; + +import org.junit.Test; + +import java.io.BufferedOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Random; + +/** + * @author cipher + */ +public class BufferExampleTest { + + private static final long WORD_NUM = 1000000000; + + @Test + public void gen() throws IOException { + Random r = new Random(); + String fileName = "word"; + + int bufferSize = 4 * 1024; + BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(fileName), bufferSize); + + long start = System.currentTimeMillis(); + + for (int i = 0; i < WORD_NUM; i++) { + for (int j = 0; j < 5; j++) { + outputStream.write(97 + r.nextInt(5)); + } + outputStream.write(' '); + } + outputStream.close(); + System.out.println(System.currentTimeMillis() - start); + } + + @Test + public void testChinese() { + String raw = "长坂桥头杀气生,横枪立马眼圆睁。一声好似轰雷震,独退曹家百万兵。"; + Charset charset = StandardCharsets.UTF_8; + byte[] bytes = charset.encode(raw).array(); + byte[] bytes2 = Arrays.copyOfRange(bytes, 0, 11); + + ByteBuffer bbuf = ByteBuffer.allocate(12); + CharBuffer cbuf = CharBuffer.allocate(12); + + bbuf.put(bytes2); + bbuf.flip(); + + charset.newDecoder().decode(bbuf, cbuf, true); + cbuf.flip(); + + char[] tmp = new char[cbuf.length()]; + if (cbuf.hasRemaining()) { + cbuf.get(tmp); + System.out.println("here:" + new String(tmp)); + } + + System.out.format("limit-pos=%d\n", bbuf.limit() - bbuf.position()); + + bytes2 = Arrays.copyOfRange(bbuf.array(), bbuf.position(), bbuf.limit()); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/buffer/WordCountTest.java b/sandbox/src/main/java/com/cipher/interview/buffer/WordCountTest.java new file mode 100644 index 0000000..39ecdc6 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/buffer/WordCountTest.java @@ -0,0 +1,122 @@ +package com.cipher.interview.buffer; + +import org.junit.Test; + +import java.io.*; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author cipher + */ +public class WordCountTest { + + private static final ExecutorService POOL = Executors.newFixedThreadPool(16); + private static final AtomicInteger count = new AtomicInteger(); + + + private static HashMap countByString(String str) { + HashMap map = new HashMap(str.length()); + StringTokenizer tokenizer = new StringTokenizer(str); + while (tokenizer.hasMoreTokens()) { + String word = tokenizer.nextToken(); + incKey(word, map, 1); + } + return map; + } + + private static void incKey(String key, HashMap map, Integer n) { + if (map.containsKey(key)) { + map.put(key, map.get(key) + n); + } else { + map.put(key, n); + } + } + + static class CountTask implements Callable> { + private final long start; + private final long end; + private final String fileName; + + public CountTask(String fileName, long start, long end) { + this.start = start; + this.end = end; + this.fileName = fileName; + + } + + @Override + public HashMap call() throws Exception { + FileChannel channel = new RandomAccessFile(this.fileName, "rw").getChannel(); + // [start, end] -> Memory + // Device -> Kernel Space -> UserSpace(buffer) -> Thread + MappedByteBuffer mbuf = channel.map(FileChannel.MapMode.READ_ONLY, this.start, this.end - this.start); + String str = StandardCharsets.US_ASCII.decode(mbuf).toString(); + return countByString(str); + } + } + + public void run(String fileName, long chunkSize) throws ExecutionException, InterruptedException { + File file = new File(fileName); + long fileSize = file.length(); + + long position = 0; + + long startTime = System.currentTimeMillis(); + ArrayList>> tasks = new ArrayList(); + while (position < fileSize) { + long next = Math.min(position + chunkSize, fileSize); + CountTask task = new CountTask(fileName, position, next); + position = next; + Future> future = POOL.submit(task); + tasks.add(future); + } + System.out.format("split to %d tasks\n", tasks.size()); + + HashMap totalMap = new HashMap(16); + for (Future> future : tasks) { + HashMap map = future.get(); + System.out.println(count.getAndIncrement()); + for (Map.Entry entry : map.entrySet()) { + incKey(entry.getKey(), totalMap, entry.getValue()); + } + } + + System.out.println("time:" + (System.currentTimeMillis() - startTime) + "ms"); + System.out.println("total:" + totalMap.size()); + System.out.println(totalMap.get("ababb")); + } + + @Test + public void count() throws ExecutionException, InterruptedException { + WordCountTest counter = new WordCountTest(); + System.out.println("processors:" + Runtime.getRuntime().availableProcessors()); + counter.run("word", 1024 * 1024 * 20); + } + + @Test + public void compareWithSingle() throws IOException { + BufferedInputStream in = new BufferedInputStream(new FileInputStream("word")); + byte[] buf = new byte[4 * 1024]; + int len; + HashMap total = new HashMap(16); + long startTime = System.currentTimeMillis(); + while ((len = in.read(buf)) != -1) { + byte[] bytes = Arrays.copyOfRange(buf, 0, len); + String str = new String(bytes); + HashMap hashMap = countByString(str); + for (Map.Entry entry : hashMap.entrySet()) { + String key = entry.getKey(); + incKey(key, total, entry.getValue()); + } + } + System.out.println("time:" + (System.currentTimeMillis() - startTime) + "ms"); + System.out.println(total.get("ababb")); + System.out.println(total.size()); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/proxy/Aspect.java b/sandbox/src/main/java/com/cipher/interview/proxy/Aspect.java new file mode 100644 index 0000000..09a7309 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/proxy/Aspect.java @@ -0,0 +1,63 @@ +package com.cipher.interview.proxy; + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * @author cipher + */ +@SuppressWarnings("unchecked") +public interface Aspect { + + /** + * before + */ + void before(); + + /** + * after + */ + void after(); + + /** + * getProxy + * + * @param cls cls + * @param aspects aspects + * @param t + * @return T + * @throws NoSuchMethodException NoSuchMethod Exception + * @throws InvocationTargetException InvocationTarget Exception + * @throws InstantiationException Instantiation Exception + * @throws IllegalAccessException IllegalAccess Exception + */ + static T getProxy(Class cls, String... aspects) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + List aspectInsts = Arrays.stream(aspects).map(name -> { + try { + Class clazz = Class.forName(name); + return (Aspect) clazz.getConstructor().newInstance(); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + }).filter(Objects::nonNull) + .collect(Collectors.toList()); + T inst = cls.getConstructor().newInstance(); + return (T) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), (o, m, args) -> { + for (Aspect aspect : aspectInsts) { + aspect.before(); + } + Object result = m.invoke(inst); + for (Aspect aspect : aspectInsts) { + aspect.after(); + } + return result; + }); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/proxy/IOrder.java b/sandbox/src/main/java/com/cipher/interview/proxy/IOrder.java new file mode 100644 index 0000000..d773db7 --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/proxy/IOrder.java @@ -0,0 +1,9 @@ +package com.cipher.interview.proxy; + +public interface IOrder { + + void pay() throws InterruptedException; + + void show(); + +} diff --git a/sandbox/src/main/java/com/cipher/interview/proxy/Order.java b/sandbox/src/main/java/com/cipher/interview/proxy/Order.java new file mode 100644 index 0000000..76b2e8a --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/proxy/Order.java @@ -0,0 +1,21 @@ +package com.cipher.interview.proxy; + +/** + * @author cipher + */ +public class Order implements IOrder { + + int state = 0; + + @Override + public void pay() throws InterruptedException { + Thread.sleep(50); + this.state = 1; + } + + @Override + public void show() { + System.out.println("order status:" + this.state); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/proxy/ProxyExampleTest.java b/sandbox/src/main/java/com/cipher/interview/proxy/ProxyExampleTest.java new file mode 100644 index 0000000..334642f --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/proxy/ProxyExampleTest.java @@ -0,0 +1,19 @@ +package com.cipher.interview.proxy; + +import org.junit.Test; + +import java.lang.reflect.InvocationTargetException; + +/** + * @author cipher + */ +public class ProxyExampleTest { + + @Test + public void testProxy() throws InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { + IOrder order = Aspect.getProxy(Order.class, "com.cipher.interview.proxy.TimeUsageAspect"); + order.pay(); + order.show(); + } + +} diff --git a/sandbox/src/main/java/com/cipher/interview/proxy/TimeUsageAspect.java b/sandbox/src/main/java/com/cipher/interview/proxy/TimeUsageAspect.java new file mode 100644 index 0000000..3f083bc --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/proxy/TimeUsageAspect.java @@ -0,0 +1,21 @@ +package com.cipher.interview.proxy; + +/** + * @author cipher + */ +public class TimeUsageAspect implements Aspect { + + long start; + + @Override + public void before() { + start = System.currentTimeMillis(); + } + + @Override + public void after() { + long usage = System.currentTimeMillis() - start; + System.out.format("time usage : %dms\n", usage); + + } +} diff --git a/sandbox/src/main/java/com/cipher/interview/stream/Event.java b/sandbox/src/main/java/com/cipher/interview/stream/Event.java new file mode 100644 index 0000000..bf74a4a --- /dev/null +++ b/sandbox/src/main/java/com/cipher/interview/stream/Event.java @@ -0,0 +1,60 @@ +package com.cipher.interview.stream; + +import java.util.function.Function; +import java.util.stream.Stream; + +/** + * @author cipher + */ +public class Event { + + T data; + + public Event(T data) { + this.data = data; + } + + static class EventData { + Integer id; + String msg; + + public EventData(Integer id, String msg) { + this.id = id; + this.msg = msg; + } + + @Override + public String toString() { + return "EventData{" + "id=" + id + ", msg='" + msg + '\'' + '}'; + } + } + + static class Transforms { + static EventData transform(Integer id) { + switch (id) { + case 0: + return new EventData(id, "Start"); + case 1: + return new EventData(id, "Running"); + case 2: + return new EventData(id, "Done"); + case 3: + return new EventData(id, "Fail"); + default: + return new EventData(id, "Error"); + } + } + } + + Event map(Function f) { + return new Event(f.apply(this.data)); + } + + public static void main(String[] args) { + Stream> s = Stream.of(new Event(1), new Event(2), new Event(0), new Event(10)); + + s.map(event -> event.map(Transforms::transform)).forEach(e -> { + System.out.println(e.data); + }); + } +}

AltStyle によって変換されたページ (->オリジナル) /