mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-20 13:31:28 +07:00
IDEA-161198 Migration from Stream API back to for loops
This commit is contained in:
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamToLoop;
|
||||
|
||||
import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToLoopReplacementContext;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.refactoring.util.LambdaRefactoringUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import one.util.streamex.EntryStream;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A helper class which represents an expression mapped to the functional interface (like lambda, method reference or normal reference)
|
||||
*
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
abstract class FunctionHelper {
|
||||
private static final Logger LOG = Logger.getInstance(FunctionHelper.class);
|
||||
|
||||
String getText() {
|
||||
return getExpression().getText();
|
||||
}
|
||||
|
||||
abstract PsiExpression getExpression();
|
||||
|
||||
/**
|
||||
* Perform an adaptation of current function helper to the replacement context with given parameter names.
|
||||
* Must be called exactly once prior using getExpression() or getText()
|
||||
*
|
||||
* @param context a context for which transformation should be performed
|
||||
* @param newNames names of the SAM parameters (the length must be exactly the same as number of SAM parameters)
|
||||
*/
|
||||
abstract void transform(StreamToLoopReplacementContext context, String... newNames);
|
||||
|
||||
/**
|
||||
* Rename the references of some variable if it's used inside this function
|
||||
*
|
||||
* @param oldName old variable name
|
||||
* @param newName new variable name
|
||||
* @param context a context
|
||||
*/
|
||||
abstract void rename(String oldName, String newName, StreamToLoopReplacementContext context);
|
||||
|
||||
abstract void registerUsedNames(Consumer<String> consumer);
|
||||
|
||||
@Nullable
|
||||
abstract String getParameterName(int index);
|
||||
|
||||
void suggestVariableName(StreamVariable var, int index) {
|
||||
String name = getParameterName(index);
|
||||
if (name != null) {
|
||||
var.addBestNameCandidate(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("null, _, _ -> null")
|
||||
@Nullable
|
||||
static FunctionHelper create(PsiExpression expression, int paramCount, boolean singleExpression) {
|
||||
if (expression instanceof PsiLambdaExpression) {
|
||||
PsiLambdaExpression lambda = (PsiLambdaExpression)expression;
|
||||
PsiParameterList list = lambda.getParameterList();
|
||||
if (list.getParametersCount() != paramCount) {
|
||||
return null;
|
||||
}
|
||||
String[] parameters = StreamEx.of(list.getParameters()).map(PsiVariable::getName).toArray(String[]::new);
|
||||
PsiExpression body = LambdaUtil.extractSingleExpressionFromBody(lambda.getBody());
|
||||
if (body == null && singleExpression) return null;
|
||||
return new LambdaFunctionHelper(body, parameters);
|
||||
}
|
||||
if (expression instanceof PsiMethodReferenceExpression) {
|
||||
PsiType functionalInterfaceType = ((PsiMethodReferenceExpression)expression).getFunctionalInterfaceType();
|
||||
PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (interfaceMethod == null) return null;
|
||||
if (interfaceMethod.getParameterList().getParametersCount() != paramCount) return null;
|
||||
return new MethodReferenceFunctionHelper(functionalInterfaceType, (PsiMethodReferenceExpression)expression);
|
||||
}
|
||||
if (expression instanceof PsiReferenceExpression && ExpressionUtils.isSimpleExpression(expression)) {
|
||||
PsiType functionalInterfaceType = expression.getType();
|
||||
PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(functionalInterfaceType);
|
||||
if (interfaceMethod == null || interfaceMethod.getParameterList().getParametersCount() != paramCount) return null;
|
||||
return new SimpleReferenceFunctionHelper(expression, interfaceMethod.getName());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames references to the variable oldName in given expression into newName
|
||||
* @param expression
|
||||
* @param oldName old name
|
||||
* @param newName new name
|
||||
* @param context context
|
||||
* @return resulting expression (might be the same as input expression) or null if expression already had references to newName,
|
||||
* so rename may merge two variables
|
||||
*/
|
||||
@NotNull
|
||||
static PsiExpression renameVarReference(@NotNull PsiExpression expression,
|
||||
String oldName,
|
||||
String newName,
|
||||
StreamToLoopReplacementContext context) {
|
||||
if(oldName.equals(newName)) return expression;
|
||||
PsiLambdaExpression lambda = (PsiLambdaExpression)context.createExpression("("+oldName+","+newName+")-> "+expression.getText());
|
||||
PsiParameter[] parameters = lambda.getParameterList().getParameters();
|
||||
PsiParameter oldVar = parameters[0];
|
||||
PsiParameter newVar = parameters[1];
|
||||
PsiElement body = lambda.getBody();
|
||||
LOG.assertTrue(body != null);
|
||||
if(ReferencesSearch.search(newVar, new LocalSearchScope(body)).findFirst() != null) {
|
||||
throw new IllegalStateException("Reference with name "+newVar+" already exists in "+lambda.getText());
|
||||
}
|
||||
for (PsiReference ref : ReferencesSearch.search(oldVar, new LocalSearchScope(body)).findAll()) {
|
||||
ref.handleElementRename(newName);
|
||||
}
|
||||
return (PsiExpression)lambda.getBody();
|
||||
}
|
||||
|
||||
static void processUsedNames(PsiElement start, Consumer<String> action) {
|
||||
start.accept(new JavaRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitVariable(PsiVariable variable) {
|
||||
super.visitVariable(variable);
|
||||
action.accept(variable.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static class MethodReferenceFunctionHelper extends FunctionHelper {
|
||||
private final String myType;
|
||||
private final String myQualifierType;
|
||||
private PsiMethodReferenceExpression myMethodRef;
|
||||
private PsiExpression myExpression;
|
||||
|
||||
public MethodReferenceFunctionHelper(PsiType functionalInterfaceType, PsiMethodReferenceExpression methodRef) {
|
||||
myMethodRef = methodRef;
|
||||
myType = functionalInterfaceType.getCanonicalText();
|
||||
PsiExpression qualifier = methodRef.getQualifierExpression();
|
||||
PsiType type = qualifier == null ? null : qualifier.getType();
|
||||
myQualifierType = type == null ? null : type.getCanonicalText();
|
||||
}
|
||||
|
||||
@Override
|
||||
PsiExpression getExpression() {
|
||||
LOG.assertTrue(myExpression != null);
|
||||
return myExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> consumer) {
|
||||
processUsedNames(myMethodRef, consumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
void transform(StreamToLoopReplacementContext context, String... newNames) {
|
||||
PsiMethodReferenceExpression methodRef = fromText(context, myMethodRef.getText());
|
||||
PsiExpression qualifier = methodRef.getQualifierExpression();
|
||||
if(qualifier != null && !ExpressionUtils.isSimpleExpression(qualifier)) {
|
||||
String type = myQualifierType;
|
||||
if(type != null) {
|
||||
String nameCandidate = "expr";
|
||||
PsiType psiType = context.createType(myQualifierType);
|
||||
SuggestedNameInfo info =
|
||||
JavaCodeStyleManager
|
||||
.getInstance(context.getProject()).suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, psiType, true);
|
||||
if(info.names.length > 0) {
|
||||
nameCandidate = info.names[0];
|
||||
}
|
||||
String expr = context.declare(nameCandidate, type, qualifier.getText());
|
||||
PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)context
|
||||
.createExpression("(" + type + " " + expr + ")->(" + myType + ")" + expr + "::" + myMethodRef.getReferenceName());
|
||||
PsiTypeCastExpression castExpr = (PsiTypeCastExpression)lambdaExpression.getBody();
|
||||
LOG.assertTrue(castExpr != null);
|
||||
methodRef = (PsiMethodReferenceExpression)castExpr.getOperand();
|
||||
}
|
||||
}
|
||||
PsiLambdaExpression lambda = LambdaRefactoringUtil.convertMethodReferenceToLambda(methodRef, true, true);
|
||||
LOG.assertTrue(lambda != null);
|
||||
PsiElement body = lambda.getBody();
|
||||
LOG.assertTrue(body instanceof PsiExpression);
|
||||
myExpression = (PsiExpression)body;
|
||||
EntryStream.zip(lambda.getParameterList().getParameters(), newNames)
|
||||
.forKeyValue((param, newName) -> myExpression = renameVarReference(myExpression, param.getName(), newName, context));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private PsiMethodReferenceExpression fromText(StreamToLoopReplacementContext context, String text) {
|
||||
PsiTypeCastExpression castExpr = (PsiTypeCastExpression)context.createExpression("(" + myType + ")" + text);
|
||||
PsiMethodReferenceExpression methodRef = (PsiMethodReferenceExpression)castExpr.getOperand();
|
||||
LOG.assertTrue(methodRef != null);
|
||||
return methodRef;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
if(oldName.equals(newName)) return;
|
||||
PsiExpression qualifier = myMethodRef.getQualifierExpression();
|
||||
if(qualifier == null) return;
|
||||
qualifier = renameVarReference(qualifier, oldName, newName, context);
|
||||
myMethodRef = fromText(context, qualifier.getText()+"::"+myMethodRef.getReferenceName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
String getParameterName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SimpleReferenceFunctionHelper extends FunctionHelper {
|
||||
private PsiExpression myReference;
|
||||
private final String myName;
|
||||
private PsiExpression myExpression;
|
||||
|
||||
public SimpleReferenceFunctionHelper(PsiExpression reference, String methodName) {
|
||||
myReference = reference;
|
||||
myName = methodName;
|
||||
}
|
||||
|
||||
@Override
|
||||
PsiExpression getExpression() {
|
||||
LOG.assertTrue(myExpression != null);
|
||||
return myExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
void transform(StreamToLoopReplacementContext context, String... newNames) {
|
||||
myExpression = context.createExpression(myReference.getText() + "." + myName + "(" + String.join(",", newNames) + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myReference = renameVarReference(myReference, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> consumer) {
|
||||
processUsedNames(myReference, consumer);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
String getParameterName(int index) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class LambdaFunctionHelper extends FunctionHelper {
|
||||
private String[] myParameters;
|
||||
private PsiExpression myBody;
|
||||
|
||||
LambdaFunctionHelper(PsiExpression body, String[] parameters) {
|
||||
myParameters = parameters;
|
||||
myBody = body;
|
||||
}
|
||||
|
||||
PsiExpression getExpression() {
|
||||
return myBody;
|
||||
}
|
||||
|
||||
void transform(StreamToLoopReplacementContext context, String... newNames) {
|
||||
LOG.assertTrue(newNames.length == myParameters.length);
|
||||
EntryStream.zip(myParameters, newNames).forKeyValue(
|
||||
(oldName, newName) -> myBody = renameVarReference(myBody, oldName, newName, context));
|
||||
}
|
||||
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
OptionalLong idx = StreamEx.of(myParameters).indexOf(newName);
|
||||
if(idx.isPresent()) {
|
||||
for(int i = 1;; i++) {
|
||||
String paramName = newName+'$'+i;
|
||||
if (!paramName.equals(oldName) &&
|
||||
!StreamEx.of(myParameters).has(paramName)) {
|
||||
try {
|
||||
myBody = renameVarReference(myBody, newName, paramName, context);
|
||||
myParameters[(int)idx.getAsLong()] = paramName;
|
||||
break;
|
||||
}
|
||||
catch(IllegalStateException ise) {
|
||||
// something is really wrong if we already have references to all newName$1, newName$2, ... newName$50
|
||||
// or probably IllegalStateException was thrown by something else: at least we don't stuck in endless loop
|
||||
if(i > 50) throw ise;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
myBody = renameVarReference(myBody, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> consumer) {
|
||||
processUsedNames(myBody, consumer);
|
||||
}
|
||||
|
||||
String getParameterName(int index) {
|
||||
return myParameters[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamToLoop;
|
||||
|
||||
import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToLoopReplacementContext;
|
||||
import com.intellij.psi.PsiExpression;
|
||||
import com.intellij.psi.PsiMethodCallExpression;
|
||||
import com.intellij.psi.util.PsiTypesUtil;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
abstract class Operation {
|
||||
boolean changesVariable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
StreamEx<StreamToLoopInspection.OperationRecord> nestedOperations() {
|
||||
return StreamEx.empty();
|
||||
}
|
||||
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {}
|
||||
|
||||
abstract String wrap(StreamVariable inVar,
|
||||
StreamVariable outVar,
|
||||
String code,
|
||||
StreamToLoopReplacementContext context);
|
||||
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
|
||||
}
|
||||
|
||||
public void suggestNames(StreamVariable inVar, StreamVariable outVar) {}
|
||||
|
||||
@Nullable
|
||||
static Operation createIntermediate(String name, PsiExpression[] args, StreamVariable outVar) {
|
||||
if(name.equals("distinct") && args.length == 0) {
|
||||
return new DistinctOperation();
|
||||
}
|
||||
if(name.equals("skip") && args.length == 1) {
|
||||
return new SkipOperation(args[0]);
|
||||
}
|
||||
if(name.equals("limit") && args.length == 1) {
|
||||
return new LimitOperation(args[0]);
|
||||
}
|
||||
if(name.equals("filter") && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
|
||||
return fn == null ? null : new FilterOperation(fn);
|
||||
}
|
||||
if(name.equals("peek") && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
|
||||
return fn == null ? null : new PeekOperation(fn);
|
||||
}
|
||||
if((name.equals("boxed") || name.equals("asLongStream") || name.equals("asDoubleStream")) && args.length == 0) {
|
||||
return new WideningOperation();
|
||||
}
|
||||
if ((name.equals("flatMap") || name.equals("flatMapToInt") || name.equals("flatMapToLong") || name.equals("flatMapToDouble")) &&
|
||||
args.length == 1) {
|
||||
return FlatMapOperation.from(outVar, args[0]);
|
||||
}
|
||||
if ((name.equals("map") ||
|
||||
name.equals("mapToInt") ||
|
||||
name.equals("mapToLong") ||
|
||||
name.equals("mapToDouble") ||
|
||||
name.equals("mapToObj")) && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
|
||||
return fn == null ? null : new MapOperation(fn);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static abstract class LambdaIntermediateOperation extends Operation {
|
||||
final FunctionHelper myFn;
|
||||
|
||||
LambdaIntermediateOperation(FunctionHelper fn) {
|
||||
myFn = fn;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myFn.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
final String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
myFn.transform(context, inVar.getName());
|
||||
return wrap(outVar, code, context);
|
||||
}
|
||||
|
||||
abstract String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context);
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myFn.rename(oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestNames(StreamVariable inVar, StreamVariable outVar) {
|
||||
myFn.suggestVariableName(inVar, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static class FilterOperation extends LambdaIntermediateOperation {
|
||||
public FilterOperation(FunctionHelper fn) {
|
||||
super(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return "if(" + myFn.getText() + ") {\n" + code + "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class PeekOperation extends LambdaIntermediateOperation {
|
||||
public PeekOperation(FunctionHelper fn) {
|
||||
super(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return myFn.getText() + ";\n" + code;
|
||||
}
|
||||
}
|
||||
|
||||
static class MapOperation extends LambdaIntermediateOperation {
|
||||
public MapOperation(FunctionHelper fn) {
|
||||
super(fn);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return outVar.getDeclaration() + " = " + myFn.getText() + ";\n" + code;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean changesVariable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class WideningOperation extends Operation {
|
||||
@Override
|
||||
String wrap(StreamVariable inVar,
|
||||
StreamVariable outVar,
|
||||
String code,
|
||||
StreamToLoopReplacementContext context) {
|
||||
return outVar.getDeclaration() + " = " + inVar + ";\n" + code;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean changesVariable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class FlatMapOperation extends Operation {
|
||||
private final @Nullable String myOriginalName;
|
||||
private final List<StreamToLoopInspection.OperationRecord> myRecords;
|
||||
|
||||
private FlatMapOperation(@Nullable String name, List<StreamToLoopInspection.OperationRecord> records) {
|
||||
myOriginalName = name;
|
||||
myRecords = records;
|
||||
}
|
||||
|
||||
@Override
|
||||
StreamEx<StreamToLoopInspection.OperationRecord> nestedOperations() {
|
||||
return StreamEx.of(myRecords).flatMap(or -> StreamEx.of(or).append(or.myOperation.nestedOperations()));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean changesVariable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestNames(StreamVariable inVar, StreamVariable outVar) {
|
||||
if(myOriginalName != null) {
|
||||
inVar.addBestNameCandidate(myOriginalName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myRecords.forEach(or -> or.myOperation.registerUsedNames(usedNameConsumer));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myRecords.forEach(or -> or.myOperation.rename(oldName, newName, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
if(myOriginalName != null && !myOriginalName.equals(inVar.getName())) {
|
||||
rename(myOriginalName, inVar.getName(), context);
|
||||
}
|
||||
StreamToLoopReplacementContext
|
||||
innerContext = new StreamToLoopReplacementContext(context, myRecords);
|
||||
String replacement = code;
|
||||
for(StreamToLoopInspection.OperationRecord or : StreamEx.ofReversed(myRecords)) {
|
||||
replacement = or.myOperation.wrap(or.myInVar, or.myOutVar, replacement, innerContext);
|
||||
}
|
||||
return StreamEx.of(innerContext.getDeclarations()).map(str -> str + "\n").joining()+replacement;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FlatMapOperation from(StreamVariable outVar, PsiExpression arg) {
|
||||
FunctionHelper fn = FunctionHelper.create(arg, 1, true);
|
||||
if(fn == null) return null;
|
||||
PsiExpression body = fn.getExpression();
|
||||
if(!(body instanceof PsiMethodCallExpression)) return null;
|
||||
PsiMethodCallExpression terminalCall = (PsiMethodCallExpression)body;
|
||||
List<StreamToLoopInspection.OperationRecord> records = StreamToLoopInspection.extractOperations(outVar, terminalCall);
|
||||
if(records == null || StreamToLoopInspection.getTerminal(records) != null) return null;
|
||||
return new FlatMapOperation(fn.getParameterName(0), records);
|
||||
}
|
||||
}
|
||||
|
||||
static class DistinctOperation extends Operation {
|
||||
@Override
|
||||
String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
String set =
|
||||
context.declare("uniqueValues", "java.util.Set<" + PsiTypesUtil.boxIfPossible(inVar.getType()) + ">", "new java.util.HashSet<>()");
|
||||
return "if(" + set + ".add(" + inVar + ")) {\n" + code + "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class SkipOperation extends Operation {
|
||||
PsiExpression myExpression;
|
||||
|
||||
SkipOperation(PsiExpression expression) {
|
||||
myExpression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myExpression = FunctionHelper.renameVarReference(myExpression, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
FunctionHelper.processUsedNames(myExpression, usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
String toSkip = context.declare("toSkip", "long", myExpression.getText());
|
||||
return "if(" + toSkip + ">0) {\n" + toSkip + "--;\ncontinue;\n}\n" + code;
|
||||
}
|
||||
}
|
||||
|
||||
static class LimitOperation extends Operation {
|
||||
PsiExpression myExpression;
|
||||
|
||||
LimitOperation(PsiExpression expression) {
|
||||
myExpression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myExpression = FunctionHelper.renameVarReference(myExpression, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
FunctionHelper.processUsedNames(myExpression, usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
String limit = context.declare("limit", "long", myExpression.getText());
|
||||
return "if(" + limit + "--==0) " + context.getBreakStatement() + code;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamToLoop;
|
||||
|
||||
import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToLoopReplacementContext;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static com.intellij.codeInspection.streamToLoop.FunctionHelper.processUsedNames;
|
||||
import static com.intellij.codeInspection.streamToLoop.FunctionHelper.renameVarReference;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
abstract class SourceOperation extends Operation {
|
||||
@Contract(value = " -> true", pure = true)
|
||||
@Override
|
||||
final boolean changesVariable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
final String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return wrap(outVar, code, context);
|
||||
}
|
||||
|
||||
abstract String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context);
|
||||
|
||||
@Nullable
|
||||
static SourceOperation createSource(PsiMethodCallExpression call) {
|
||||
PsiExpression[] args = call.getArgumentList().getExpressions();
|
||||
PsiType callType = call.getType();
|
||||
if(callType == null) return null;
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if(method == null) return null;
|
||||
String name = method.getName();
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if(aClass == null) return null;
|
||||
String className = aClass.getQualifiedName();
|
||||
if(className == null) return null;
|
||||
if ((name.equals("range") || name.equals("rangeClosed")) && args.length == 2 && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && (className.equals(CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM) ||
|
||||
className.equals(CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM))) {
|
||||
return new RangeSource(args[0], args[1], name.equals("rangeClosed"));
|
||||
}
|
||||
if (name.equals("of") && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && className.startsWith("java.util.stream.")) {
|
||||
if(args.length == 1) {
|
||||
PsiType type = args[0].getType();
|
||||
if(type instanceof PsiArrayType) {
|
||||
PsiType componentType = ((PsiArrayType)type).getComponentType();
|
||||
if(StreamToLoopInspection.getStreamElementType(callType).isAssignableFrom(componentType)) {
|
||||
return new ForEachSource(args[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ExplicitSource(args);
|
||||
}
|
||||
if (name.equals("generate") && args.length == 1 && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && className.startsWith("java.util.stream.")) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 0, true);
|
||||
return fn == null ? null : new GenerateSource(fn);
|
||||
}
|
||||
if (name.equals("iterate") && args.length == 2 && method.getModifierList().hasExplicitModifier(
|
||||
PsiModifier.STATIC) && className.startsWith("java.util.stream.")) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[1], 1, true);
|
||||
return fn == null ? null : new IterateSource(args[0], fn);
|
||||
}
|
||||
if (name.equals("stream") && args.length == 0 &&
|
||||
InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_COLLECTION)) {
|
||||
return new ForEachSource(call.getMethodExpression().getQualifierExpression());
|
||||
}
|
||||
if (name.equals("stream") && args.length == 1 &&
|
||||
CommonClassNames.JAVA_UTIL_ARRAYS.equals(className)) {
|
||||
return new ForEachSource(args[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class ForEachSource extends SourceOperation {
|
||||
private PsiExpression myQualifier;
|
||||
|
||||
ForEachSource(PsiExpression qualifier) {
|
||||
myQualifier = qualifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myQualifier = renameVarReference(myQualifier, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
processUsedNames(myQualifier, usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestNames(StreamVariable inVar, StreamVariable outVar) {
|
||||
if(myQualifier instanceof PsiReferenceExpression) {
|
||||
String name = ((PsiReferenceExpression)myQualifier).getReferenceName();
|
||||
if(name != null) {
|
||||
name = StringUtil.unpluralize(name);
|
||||
if(name != null) {
|
||||
outVar.addOtherNameCandidate(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return context.getLoopLabel() +
|
||||
"for(" + outVar.getDeclaration() + ": " + (myQualifier == null ? "this" : myQualifier.getText()) + ") {" + code + "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class ExplicitSource extends SourceOperation {
|
||||
private PsiExpression[] myArgList;
|
||||
|
||||
ExplicitSource(PsiExpression[] argList) {
|
||||
myArgList = argList;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
Arrays.asList(myArgList).replaceAll(arg -> renameVarReference(arg, oldName, newName, context));
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
for(PsiExpression arg : myArgList) {
|
||||
processUsedNames(arg, usedNameConsumer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
String type = outVar.getType();
|
||||
String args = StreamEx.of(myArgList).map(PsiExpression::getText).joining(", ");
|
||||
// TODO: remove type argument if redundant
|
||||
String collection =
|
||||
TypeConversionUtil.isPrimitive(type) ? "new " + type + "[] {" + args + "}" : "java.util.Arrays.<" + type + ">asList(" + args + ")";
|
||||
return context.getLoopLabel() +
|
||||
"for(" + outVar.getDeclaration() + ": " + collection + ") {" + code + "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class GenerateSource extends SourceOperation {
|
||||
private FunctionHelper myFn;
|
||||
|
||||
GenerateSource(FunctionHelper fn) {
|
||||
myFn = fn;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myFn.rename(oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myFn.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
myFn.transform(context);
|
||||
return context.getLoopLabel() +
|
||||
"while(true) {\n" +
|
||||
outVar.getDeclaration() + "=" + myFn.getText() + ";\n" + code +
|
||||
"}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class IterateSource extends SourceOperation {
|
||||
private PsiExpression myInitializer;
|
||||
private FunctionHelper myFn;
|
||||
|
||||
IterateSource(PsiExpression initializer, FunctionHelper fn) {
|
||||
myInitializer = initializer;
|
||||
myFn = fn;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myInitializer = renameVarReference(myInitializer, oldName, newName, context);
|
||||
myFn.rename(oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
processUsedNames(myInitializer, usedNameConsumer);
|
||||
myFn.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestNames(StreamVariable inVar, StreamVariable outVar) {
|
||||
myFn.suggestVariableName(outVar, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
myFn.transform(context, outVar.getName());
|
||||
return context.getLoopLabel() +
|
||||
"for(" + outVar.getDeclaration() + "=" + myInitializer.getText() + ";;" +
|
||||
outVar + "=" + myFn.getText() + ") {\n" + code + "}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class RangeSource extends SourceOperation {
|
||||
private PsiExpression myOrigin;
|
||||
private PsiExpression myBound;
|
||||
private boolean myInclusive;
|
||||
|
||||
RangeSource(PsiExpression origin, PsiExpression bound, boolean inclusive) {
|
||||
myOrigin = origin;
|
||||
myBound = bound;
|
||||
myInclusive = inclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
myOrigin = renameVarReference(myOrigin, oldName, newName, context);
|
||||
myBound = renameVarReference(myBound, oldName, newName, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
processUsedNames(myOrigin, usedNameConsumer);
|
||||
processUsedNames(myBound, usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String wrap(StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
String bound;
|
||||
if(!ExpressionUtils.isSimpleExpression(myBound)) {
|
||||
bound = context.declare("bound", outVar.getType(), myBound.getText());
|
||||
} else {
|
||||
bound = myBound.getText();
|
||||
}
|
||||
return context.getLoopLabel() +
|
||||
"for(" + outVar.getDeclaration() + " = " + myOrigin.getText() + ";" +
|
||||
outVar + (myInclusive ? "<=" : "<") + bound + ";" +
|
||||
outVar + "++) {\n" +
|
||||
code + "}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamToLoop;
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService;
|
||||
import com.intellij.codeInspection.BaseJavaBatchLocalInspectionTool;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ProblemsHolder;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import one.util.streamex.IntStreamEx;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.codeInspection.streamToLoop.Operation.FlatMapOperation;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
private static final Logger LOG = Logger.getInstance(StreamToLoopInspection.class);
|
||||
|
||||
// To quickly filter out most of the non-interesting method calls
|
||||
private static final Set<String> SUPPORTED_TERMINALS = StreamEx.of("count", "sum", "summaryStatistics", "reduce", "collect",
|
||||
"findFirst", "findAny", "anyMatch", "allMatch", "noneMatch",
|
||||
"toArray", "average", "forEach", "forEachOrdered").toSet();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
|
||||
if (!PsiUtil.isLanguageLevel8OrHigher(holder.getFile())) {
|
||||
return PsiElementVisitor.EMPTY_VISITOR;
|
||||
}
|
||||
return new JavaElementVisitor() {
|
||||
@Override
|
||||
public void visitMethodCallExpression(PsiMethodCallExpression call) {
|
||||
super.visitMethodCallExpression(call);
|
||||
PsiReferenceExpression expression = call.getMethodExpression();
|
||||
if (!SUPPORTED_TERMINALS.contains(expression.getReferenceName()) || !isSupportedCodeLocation(call)) return;
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if(method == null) return;
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if(!InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) return;
|
||||
PsiMethodCallExpression currentCall = call;
|
||||
while(true) {
|
||||
Operation op = createOperationFromCall(StreamVariable.STUB, currentCall);
|
||||
if(op == null) return;
|
||||
if(op instanceof SourceOperation) {
|
||||
holder.registerProblem(call, "Replace stream API chain with loop", new ReplaceStreamWithLoopFix());
|
||||
return;
|
||||
}
|
||||
PsiExpression qualifier = currentCall.getMethodExpression().getQualifierExpression();
|
||||
if(!(qualifier instanceof PsiMethodCallExpression)) return;
|
||||
currentCall = (PsiMethodCallExpression)qualifier;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isSupportedCodeLocation(PsiMethodCallExpression call) {
|
||||
PsiElement cur = call;
|
||||
PsiElement parent = cur.getParent();
|
||||
while(parent instanceof PsiExpression) {
|
||||
// TODO: support in single expression lambdas
|
||||
if(parent instanceof PsiLambdaExpression) {
|
||||
return false;
|
||||
}
|
||||
if(parent instanceof PsiPolyadicExpression) {
|
||||
PsiPolyadicExpression polyadicExpression = (PsiPolyadicExpression)parent;
|
||||
IElementType type = polyadicExpression.getOperationTokenType();
|
||||
if ((type.equals(JavaTokenType.ANDAND) || type.equals(JavaTokenType.OROR)) && polyadicExpression.getOperands()[0] != cur) {
|
||||
// not the first in the &&/|| chain: we cannot properly generate code which would short-circuit as well
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(parent instanceof PsiConditionalExpression && ((PsiConditionalExpression)parent).getCondition() != cur) {
|
||||
return false;
|
||||
}
|
||||
cur = parent;
|
||||
parent = cur.getParent();
|
||||
}
|
||||
if(parent instanceof PsiExportsStatement || parent instanceof PsiReturnStatement || parent instanceof PsiExpressionStatement) return true;
|
||||
if(parent instanceof PsiLocalVariable) {
|
||||
PsiElement grandParent = parent.getParent();
|
||||
if(grandParent instanceof PsiDeclarationStatement && ((PsiDeclarationStatement)grandParent).getDeclaredElements().length == 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if(parent instanceof PsiForeachStatement && ((PsiForeachStatement)parent).getIteratedValue() == cur) return true;
|
||||
if(parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getCondition() == cur) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Operation createOperationFromCall(StreamVariable outVar, PsiMethodCallExpression call) {
|
||||
PsiMethod method = call.resolveMethod();
|
||||
if(method == null) return null;
|
||||
PsiClass aClass = method.getContainingClass();
|
||||
if(aClass == null) return null;
|
||||
PsiExpression[] args = call.getArgumentList().getExpressions();
|
||||
String name = method.getName();
|
||||
String className = aClass.getQualifiedName();
|
||||
if(className == null) return null;
|
||||
PsiType callType = call.getType();
|
||||
if(callType == null) return null;
|
||||
if(InheritanceUtil.isInheritor(aClass, CommonClassNames.JAVA_UTIL_STREAM_BASE_STREAM)) {
|
||||
Operation op = Operation.createIntermediate(name, args, outVar);
|
||||
if (op != null) return op;
|
||||
op = TerminalOperation.createTerminal(name, args, callType, className, call.getParent() instanceof PsiExpressionStatement);
|
||||
if(op != null) return op;
|
||||
}
|
||||
return SourceOperation.createSource(call);
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
static List<OperationRecord> extractOperations(StreamVariable outVar, PsiMethodCallExpression terminalCall) {
|
||||
List<OperationRecord> operations = new ArrayList<>();
|
||||
PsiMethodCallExpression currentCall = terminalCall;
|
||||
StreamVariable lastVar = outVar;
|
||||
while(true) {
|
||||
Operation op = createOperationFromCall(lastVar, currentCall);
|
||||
if(op == null) return null;
|
||||
OperationRecord or = new OperationRecord();
|
||||
or.myOperation = op;
|
||||
or.myOutVar = lastVar;
|
||||
operations.add(or);
|
||||
if(op instanceof SourceOperation) {
|
||||
or.myInVar = StreamVariable.STUB;
|
||||
Collections.reverse(operations);
|
||||
return operations;
|
||||
}
|
||||
PsiExpression qualifier = currentCall.getMethodExpression().getQualifierExpression();
|
||||
if(!(qualifier instanceof PsiMethodCallExpression)) return null;
|
||||
currentCall = (PsiMethodCallExpression)qualifier;
|
||||
if(op.changesVariable()) {
|
||||
PsiType type = getStreamElementType(currentCall.getType());
|
||||
if(type == null) return null;
|
||||
lastVar = new StreamVariable(type);
|
||||
}
|
||||
or.myInVar = lastVar;
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
static TerminalOperation getTerminal(List<OperationRecord> operations) {
|
||||
if (operations == null || operations.isEmpty()) return null;
|
||||
OperationRecord record = operations.get(operations.size()-1);
|
||||
if(record.myOperation instanceof TerminalOperation) {
|
||||
return (TerminalOperation)record.myOperation;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static class ReplaceStreamWithLoopFix implements LocalQuickFix {
|
||||
@Nls
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return "Replace Stream API chain with loop";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiElement element = descriptor.getStartElement();
|
||||
if(!(element instanceof PsiMethodCallExpression)) return;
|
||||
PsiMethodCallExpression terminalCall = (PsiMethodCallExpression)element;
|
||||
if(!isSupportedCodeLocation(terminalCall)) return;
|
||||
boolean inReturn = terminalCall.getParent() instanceof PsiReturnStatement;
|
||||
List<OperationRecord> operations = extractOperations(StreamVariable.STUB, terminalCall);
|
||||
TerminalOperation terminal = getTerminal(operations);
|
||||
if (terminal == null) return;
|
||||
annotateOperations(project, operations);
|
||||
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
|
||||
if(!FileModificationService.getInstance().preparePsiElementForWrite(element)) return;
|
||||
terminalCall = ensureCodeBlock(terminalCall, factory);
|
||||
if(terminalCall == null) return;
|
||||
PsiStatement statement = PsiTreeUtil.getParentOfType(terminalCall, PsiStatement.class);
|
||||
LOG.assertTrue(statement != null);
|
||||
PsiElement temporaryStreamPlaceholder = terminalCall.replace(factory.createExpressionFromText("$streamReplacement$", terminalCall));
|
||||
try {
|
||||
StreamToLoopReplacementContext context = new StreamToLoopReplacementContext(statement, operations, inReturn);
|
||||
registerVariables(operations, context);
|
||||
String replacement = "";
|
||||
for (OperationRecord or : StreamEx.ofReversed(operations)) {
|
||||
replacement = or.myOperation.wrap(or.myInVar, or.myOutVar, replacement, context);
|
||||
}
|
||||
for (String declaration : context.getDeclarations()) {
|
||||
addStatement(project, statement, factory.createStatementFromText(declaration, statement));
|
||||
}
|
||||
for (PsiStatement addedStatement : ((PsiBlockStatement)factory.createStatementFromText("{" + replacement + "}", statement))
|
||||
.getCodeBlock().getStatements()) {
|
||||
addStatement(project, statement, addedStatement);
|
||||
}
|
||||
String finisher = context.getFinisher();
|
||||
if (finisher == null) {
|
||||
temporaryStreamPlaceholder.delete();
|
||||
}
|
||||
else {
|
||||
temporaryStreamPlaceholder.replace(factory.createExpressionFromText(finisher, temporaryStreamPlaceholder));
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if(temporaryStreamPlaceholder.isPhysical()) {
|
||||
// Just in case if something went wrong: at least try to restore the original stream code
|
||||
temporaryStreamPlaceholder.replace(factory.createExpressionFromText(terminalCall.getText(), temporaryStreamPlaceholder));
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
void addStatement(@NotNull Project project, PsiStatement statement, PsiStatement context) {
|
||||
CodeStyleManager.getInstance(project)
|
||||
.reformat(JavaCodeStyleManager.getInstance(project).shortenClassReferences(statement.getParent().addBefore(context, statement)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethodCallExpression ensureCodeBlock(PsiMethodCallExpression expression, PsiElementFactory factory) {
|
||||
PsiStatement statement = PsiTreeUtil.getParentOfType(expression, PsiStatement.class);
|
||||
if(statement == null) return null;
|
||||
if(!(statement.getParent() instanceof PsiCodeBlock)) {
|
||||
PsiElement nameElement = expression.getMethodExpression().getReferenceNameElement();
|
||||
if(nameElement == null) return null;
|
||||
int delta = nameElement.getTextOffset() - statement.getTextOffset();
|
||||
PsiElement blockStatement = statement.replace(factory.createStatementFromText("{" + statement.getText() + "}", statement));
|
||||
PsiStatement newStatement = ((PsiBlockStatement)blockStatement).getCodeBlock().getStatements()[0];
|
||||
int targetOffset = newStatement.getTextOffset() + delta;
|
||||
PsiElement element = PsiUtilCore.getElementAtOffset(newStatement.getContainingFile(), targetOffset);
|
||||
PsiMethodCallExpression newExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
|
||||
LOG.assertTrue(newExpression != null);
|
||||
return newExpression;
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private static StreamEx<OperationRecord> allOperations(List<OperationRecord> operations) {
|
||||
return StreamEx.of(operations)
|
||||
.flatMap(or -> or.myOperation.nestedOperations().append(or));
|
||||
}
|
||||
|
||||
private static void annotateOperations(@NotNull Project project, List<OperationRecord> operations) {
|
||||
JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(project);
|
||||
allOperations(operations)
|
||||
.peek(or -> or.myOperation.suggestNames(or.myInVar, or.myOutVar))
|
||||
.flatMap(or -> StreamEx.of(or.myInVar, or.myOutVar)).distinct()
|
||||
.forEach(var -> var.addCandidatesFromType(javaCodeStyleManager));
|
||||
}
|
||||
|
||||
private static void registerVariables(List<OperationRecord> operations, StreamToLoopReplacementContext context) {
|
||||
allOperations(operations).map(or -> or.myOperation).forEach(op -> op.registerUsedNames(context::addUsedVar));
|
||||
allOperations(operations).map(or -> or.myInVar).distinct().forEach(var -> var.register(context));
|
||||
}
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
static PsiType getStreamElementType(PsiType type) {
|
||||
if(!(type instanceof PsiClassType)) return null;
|
||||
PsiClass aClass = ((PsiClassType)type).resolve();
|
||||
if(InheritanceUtil.isInheritor(aClass, false, CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM)) {
|
||||
return PsiType.INT;
|
||||
}
|
||||
if(InheritanceUtil.isInheritor(aClass, false, CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM)) {
|
||||
return PsiType.LONG;
|
||||
}
|
||||
if(InheritanceUtil.isInheritor(aClass, false, CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM)) {
|
||||
return PsiType.DOUBLE;
|
||||
}
|
||||
PsiType[] parameters = ((PsiClassType)type).getParameters();
|
||||
if(parameters.length != 1) return null;
|
||||
PsiType streamType = parameters[0];
|
||||
if(streamType instanceof PsiCapturedWildcardType) {
|
||||
streamType = ((PsiCapturedWildcardType)streamType).getUpperBound();
|
||||
}
|
||||
return streamType;
|
||||
}
|
||||
|
||||
static class StreamToLoopReplacementContext {
|
||||
private final boolean myHasNestedLoops;
|
||||
private final boolean myInReturn;
|
||||
private final String mySuffix;
|
||||
private final PsiStatement myStatement;
|
||||
private final Set<String> myUsedNames;
|
||||
private final Set<String> myUsedLabels;
|
||||
private final List<String> myDeclarations = new ArrayList<>();
|
||||
private String myLabel;
|
||||
private String myFinisher;
|
||||
|
||||
StreamToLoopReplacementContext(PsiStatement statement, List<OperationRecord> records, boolean inReturn) {
|
||||
myStatement = statement;
|
||||
myHasNestedLoops = records.stream().anyMatch(or -> or.myOperation instanceof FlatMapOperation);
|
||||
myInReturn = inReturn;
|
||||
mySuffix = myHasNestedLoops ? "Outer" : "";
|
||||
myUsedNames = new HashSet<>();
|
||||
myUsedLabels = StreamEx.iterate(statement, Objects::nonNull, PsiElement::getParent).select(PsiLabeledStatement.class)
|
||||
.map(PsiLabeledStatement::getName).toSet();
|
||||
}
|
||||
|
||||
StreamToLoopReplacementContext(StreamToLoopReplacementContext parentContext, List<OperationRecord> records) {
|
||||
myUsedNames = parentContext.myUsedNames;
|
||||
myUsedLabels = parentContext.myUsedLabels;
|
||||
myInReturn = false;
|
||||
myStatement = parentContext.myStatement;
|
||||
myHasNestedLoops = records.stream().anyMatch(or -> or.myOperation instanceof FlatMapOperation);
|
||||
mySuffix = "Inner";
|
||||
}
|
||||
|
||||
public void addUsedVar(String name) {
|
||||
myUsedNames.add(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String allocateLabel() {
|
||||
if(!myHasNestedLoops) return null;
|
||||
if(myLabel == null) {
|
||||
String base = mySuffix.toUpperCase(Locale.ENGLISH);
|
||||
myLabel = IntStreamEx.ints().mapToObj(i -> i == 0 ? base : base + i)
|
||||
.remove(myUsedLabels::contains).findFirst().orElseThrow(IllegalArgumentException::new);
|
||||
myUsedLabels.add(myLabel);
|
||||
}
|
||||
return myLabel;
|
||||
}
|
||||
|
||||
public String getLoopLabel() {
|
||||
return myLabel == null ? "" : myLabel + ":\n";
|
||||
}
|
||||
|
||||
public String getBreakStatement() {
|
||||
String label = allocateLabel();
|
||||
return label == null ? "break;\n" : "break "+label+";\n";
|
||||
}
|
||||
|
||||
public List<String> getDeclarations() {
|
||||
return myDeclarations;
|
||||
}
|
||||
|
||||
public String registerVarName(Collection<String> variants) {
|
||||
// TODO: avoid introducing conflicts with nested scopes (variables declared in lambdas, nested lambdas)
|
||||
if(variants.isEmpty()) {
|
||||
return registerVarName(Collections.singleton("val"));
|
||||
}
|
||||
for(int idx = 0; ; idx++) {
|
||||
for(String variant : variants) {
|
||||
String name = idx == 0 ? variant : variant + idx;
|
||||
if(!isUsed(name)) {
|
||||
myUsedNames.add(name);
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUsed(String varName) {
|
||||
if(myUsedNames.contains(varName)) return true;
|
||||
// TODO: cleaner solution
|
||||
return !varName.equals(JavaCodeStyleManager.getInstance(myStatement.getProject()).suggestUniqueVariableName(varName, myStatement, true));
|
||||
}
|
||||
|
||||
public String declare(String desiredName, String type, String initializer) {
|
||||
String name = registerVarName(
|
||||
mySuffix.isEmpty() ? Collections.singleton(desiredName) : Arrays.asList(desiredName, desiredName + mySuffix));
|
||||
myDeclarations.add(type + " " + name + " = " + initializer + ";");
|
||||
return name;
|
||||
}
|
||||
|
||||
public String assignAndBreak(String desiredName, String type, String foundValue, String notFoundValue) {
|
||||
if(myInReturn) {
|
||||
setFinisher(notFoundValue);
|
||||
return "return "+foundValue+";";
|
||||
}
|
||||
String found = declareResult(desiredName, type, notFoundValue);
|
||||
return found + " = " +foundValue+";\n" + getBreakStatement();
|
||||
}
|
||||
|
||||
public String declareResult(String desiredName, String type, String initializer) {
|
||||
String name = registerVarName(Arrays.asList(desiredName, "result"));
|
||||
myDeclarations.add(type + " " + name + " = " + initializer + ";");
|
||||
if(myFinisher != null) {
|
||||
throw new IllegalStateException("Finisher is already defined");
|
||||
}
|
||||
setFinisher(name);
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getFinisher() {
|
||||
return myFinisher;
|
||||
}
|
||||
|
||||
public void setFinisher(String finisher) {
|
||||
myFinisher = finisher;
|
||||
}
|
||||
|
||||
public Project getProject() {
|
||||
return myStatement.getProject();
|
||||
}
|
||||
|
||||
public PsiExpression createExpression(String text) {
|
||||
return JavaPsiFacade.getElementFactory(myStatement.getProject()).createExpressionFromText(text, myStatement);
|
||||
}
|
||||
|
||||
public PsiType createType(String text) {
|
||||
return JavaPsiFacade.getElementFactory(myStatement.getProject()).createTypeFromText(text, myStatement);
|
||||
}
|
||||
}
|
||||
|
||||
static class OperationRecord {
|
||||
Operation myOperation;
|
||||
StreamVariable myInVar, myOutVar;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamToLoop;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class represents a variable which holds stream element. Its lifecycle is the following:
|
||||
* 1. Construction: fast, in case you don't need to perform a fix actually
|
||||
* 2. Gather name candidates (addBestNameCandidate/addOtherNameCandidate can be called).
|
||||
* 3. addCandidatesFromType called which adds name candidates based on type
|
||||
* (until this stage no changes in original file should be performed)
|
||||
* 4. Register variable in {@code StreamToLoopReplacementContext}: actual variable name is assigned here
|
||||
* 5. Usage in code generation: getName()/getType() could be called.
|
||||
*
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
class StreamVariable {
|
||||
private static final Logger LOG = Logger.getInstance(StreamVariable.class);
|
||||
|
||||
static StreamVariable STUB = new StreamVariable(PsiType.VOID) {
|
||||
@Override
|
||||
public void addBestNameCandidate(String candidate) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCandidatesFromType(JavaCodeStyleManager manager) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void register(StreamToLoopInspection.StreamToLoopReplacementContext context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "###STUB###";
|
||||
}
|
||||
};
|
||||
|
||||
String myName;
|
||||
String myType;
|
||||
PsiType myPsiType;
|
||||
|
||||
private Collection<String> myBestCandidates = new LinkedHashSet<>();
|
||||
private Collection<String> myOtherCandidates = new LinkedHashSet<>();
|
||||
|
||||
StreamVariable(@NotNull PsiType type) {
|
||||
myPsiType = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register best name candidate for this variable (like lambda argument which was explicitly present in the original code).
|
||||
*
|
||||
* @param candidate name candidate
|
||||
*/
|
||||
void addBestNameCandidate(String candidate) {
|
||||
myBestCandidates.add(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register normal name candidate for this variable (for example, derived using unpluralize from collection name, etc.)
|
||||
*
|
||||
* @param candidate name candidate
|
||||
*/
|
||||
void addOtherNameCandidate(String candidate) {
|
||||
myOtherCandidates.add(candidate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register name candidates based on variable type.
|
||||
* This must be called only once and only after addBestNameCandidate/addOtherNameCandidate.
|
||||
*
|
||||
* @param manager project-specific {@link JavaCodeStyleManager}
|
||||
*/
|
||||
void addCandidatesFromType(JavaCodeStyleManager manager) {
|
||||
LOG.assertTrue(myPsiType != null);
|
||||
LOG.assertTrue(myType == null);
|
||||
myOtherCandidates.addAll(Arrays.asList(manager.suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, myPsiType, true).names));
|
||||
myType = myPsiType.getCanonicalText();
|
||||
myPsiType = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register variable within {@link com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToLoopReplacementContext}.
|
||||
* Must be called once after all name candidates are registered. Now variable gets an actual name.
|
||||
*
|
||||
* @param context context to use
|
||||
*/
|
||||
void register(StreamToLoopInspection.StreamToLoopReplacementContext context) {
|
||||
LOG.assertTrue(myName == null);
|
||||
List<String> variants = StreamEx.of(myBestCandidates).append(myOtherCandidates).distinct().toList();
|
||||
if (variants.isEmpty()) variants.add("val");
|
||||
myName = context.registerVarName(variants);
|
||||
myBestCandidates = myOtherCandidates = null;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
LOG.assertTrue(myName != null);
|
||||
return myName;
|
||||
}
|
||||
|
||||
String getType() {
|
||||
LOG.assertTrue(myType != null);
|
||||
return myType;
|
||||
}
|
||||
|
||||
String getDeclaration() {
|
||||
return getType() + " " + getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (myName == null) {
|
||||
return "###(unregistered: " + myBestCandidates + "|" + myOtherCandidates + ")###";
|
||||
}
|
||||
return myName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.streamToLoop;
|
||||
|
||||
import com.intellij.codeInspection.streamToLoop.StreamToLoopInspection.StreamToLoopReplacementContext;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.siyeh.ig.psiutils.BoolUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
abstract class TerminalOperation extends Operation {
|
||||
@Override
|
||||
final String wrap(StreamVariable inVar, StreamVariable outVar, String code, StreamToLoopReplacementContext context) {
|
||||
return generate(inVar, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
final void rename(String oldName, String newName, StreamToLoopReplacementContext context) {
|
||||
throw new IllegalStateException("Should not be called for terminal operation (tried to rename " + oldName + " -> " + newName + ")");
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean changesVariable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract String generate(StreamVariable inVar, StreamToLoopReplacementContext context);
|
||||
|
||||
@NotNull
|
||||
@Contract(pure = true)
|
||||
private static String getOptionalClass(String type) {
|
||||
switch (type) {
|
||||
case "int":
|
||||
return "java.util.OptionalInt";
|
||||
case "long":
|
||||
return "java.util.OptionalLong";
|
||||
case "double":
|
||||
return "java.util.OptionalDouble";
|
||||
default:
|
||||
return "java.util.Optional";
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static TerminalOperation createTerminal(String name, PsiExpression[] args, PsiType callType, String className, boolean isVoid) {
|
||||
if(isVoid) {
|
||||
if ((name.equals("forEach") || name.equals("forEachOrdered")) && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
|
||||
return fn == null ? null : new ForEachTerminalOperation(fn);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if(name.equals("count") && args.length == 0) {
|
||||
return new AccumulatedTerminalOperation("count", "long", "0", "{acc}++;");
|
||||
}
|
||||
if(name.equals("sum") && args.length == 0) {
|
||||
return new AccumulatedTerminalOperation("sum", callType.getCanonicalText(), "0", "{acc}+={item};");
|
||||
}
|
||||
if(name.equals("average") && args.length == 0) {
|
||||
if(className.equals(CommonClassNames.JAVA_UTIL_STREAM_DOUBLE_STREAM)) {
|
||||
return new AverageTerminalOperation(true);
|
||||
}
|
||||
else if(className.equals(CommonClassNames.JAVA_UTIL_STREAM_INT_STREAM) ||
|
||||
className.equals(CommonClassNames.JAVA_UTIL_STREAM_LONG_STREAM)) {
|
||||
return new AverageTerminalOperation(false);
|
||||
}
|
||||
}
|
||||
if(name.equals("summaryStatistics") && args.length == 0) {
|
||||
return new AccumulatedTerminalOperation("stat", callType.getCanonicalText(), "new " + callType.getCanonicalText() + "()",
|
||||
"{acc}.accept({item});");
|
||||
}
|
||||
if((name.equals("findFirst") || name.equals("findAny")) && args.length == 0) {
|
||||
return new FindTerminalOperation(callType.getCanonicalText());
|
||||
}
|
||||
if((name.equals("anyMatch") || name.equals("allMatch") || name.equals("noneMatch")) && args.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 1, true);
|
||||
return fn == null ? null : new MatchTerminalOperation(fn, name);
|
||||
}
|
||||
if(name.equals("reduce")) {
|
||||
if(args.length == 2 || args.length == 3) {
|
||||
FunctionHelper fn = FunctionHelper.create(args[1], 2, true);
|
||||
if(fn != null) {
|
||||
return new ReduceTerminalOperation(args[0], fn, callType.getCanonicalText());
|
||||
}
|
||||
}
|
||||
if(args.length == 1) {
|
||||
PsiType optionalElementType = getOptionalElementType(callType);
|
||||
FunctionHelper fn = FunctionHelper.create(args[0], 2, true);
|
||||
if(fn != null && optionalElementType != null) {
|
||||
return new ReduceToOptionalTerminalOperation(fn, optionalElementType.getCanonicalText());
|
||||
}
|
||||
}
|
||||
}
|
||||
if(name.equals("toArray") && args.length < 2) {
|
||||
if(!(callType instanceof PsiArrayType)) return null;
|
||||
PsiType componentType = ((PsiArrayType)callType).getComponentType();
|
||||
if (componentType instanceof PsiPrimitiveType) {
|
||||
if(args.length == 0) return new ToPrimitiveArrayTerminalOperation(componentType.getCanonicalText());
|
||||
}
|
||||
else {
|
||||
String arr = "";
|
||||
if(args.length == 1) {
|
||||
if(!(args[0] instanceof PsiMethodReferenceExpression)) return null;
|
||||
PsiMethodReferenceExpression arrCtor = (PsiMethodReferenceExpression)args[0];
|
||||
if(!arrCtor.isConstructor()) return null;
|
||||
PsiTypeElement typeElement = arrCtor.getQualifierType();
|
||||
if(typeElement == null) return null;
|
||||
PsiType type = typeElement.getType();
|
||||
if(!(type instanceof PsiArrayType)) return null;
|
||||
arr = "new "+type.getCanonicalText().replaceFirst("\\[]", "[0]");
|
||||
}
|
||||
return new AccumulatedTerminalOperation("list", CommonClassNames.JAVA_UTIL_LIST + "<" + componentType.getCanonicalText() + ">",
|
||||
"new "+ CommonClassNames.JAVA_UTIL_ARRAY_LIST+"<>()", "{acc}.add({item});",
|
||||
"{acc}.toArray("+arr+")");
|
||||
}
|
||||
}
|
||||
if(name.equals("collect") && args.length == 1) {
|
||||
if(args[0] instanceof PsiMethodCallExpression) {
|
||||
PsiMethodCallExpression collectorCall = (PsiMethodCallExpression)args[0];
|
||||
PsiExpression[] collectorArgs = collectorCall.getArgumentList().getExpressions();
|
||||
PsiMethod collector = collectorCall.resolveMethod();
|
||||
if(collector == null) return null;
|
||||
PsiClass collectorClass = collector.getContainingClass();
|
||||
if(collectorClass != null && CommonClassNames.JAVA_UTIL_STREAM_COLLECTORS.equals(collectorClass.getQualifiedName())) {
|
||||
if(collector.getName().equals("toList") && collectorArgs.length == 0) {
|
||||
return AccumulatedTerminalOperation.toCollection(callType, CommonClassNames.JAVA_UTIL_ARRAY_LIST, "list");
|
||||
}
|
||||
if(collector.getName().equals("toSet") && collectorArgs.length == 0) {
|
||||
return AccumulatedTerminalOperation.toCollection(callType, CommonClassNames.JAVA_UTIL_HASH_SET, "set");
|
||||
}
|
||||
if(collector.getName().equals("toCollection") && collectorArgs.length == 1) {
|
||||
FunctionHelper fn = FunctionHelper.create(collectorArgs[0], 0, true);
|
||||
if(fn != null) {
|
||||
return new ToCollectionTerminalOperation(fn, callType);
|
||||
}
|
||||
}
|
||||
if(collector.getName().equals("reducing") && collectorArgs.length == 2) {
|
||||
FunctionHelper fn = FunctionHelper.create(collectorArgs[1], 2, true);
|
||||
if(fn != null) {
|
||||
return new ReduceTerminalOperation(collectorArgs[0], fn, callType.getCanonicalText());
|
||||
}
|
||||
}
|
||||
if(collector.getName().equals("reducing") && collectorArgs.length == 1) {
|
||||
PsiType optionalElementType = getOptionalElementType(callType);
|
||||
FunctionHelper fn = FunctionHelper.create(collectorArgs[0], 2, true);
|
||||
if(fn != null && optionalElementType != null) {
|
||||
return new ReduceToOptionalTerminalOperation(fn, optionalElementType.getCanonicalText());
|
||||
}
|
||||
}
|
||||
if(collector.getName().equals("joining")) {
|
||||
if(collectorArgs.length == 0) {
|
||||
return new AccumulatedTerminalOperation("sb", CommonClassNames.JAVA_LANG_STRING_BUILDER,
|
||||
"new " + CommonClassNames.JAVA_LANG_STRING_BUILDER + "()", "{acc}.append({item});",
|
||||
"{acc}.toString()");
|
||||
}
|
||||
if(collectorArgs.length == 1 || collectorArgs.length == 3) {
|
||||
String initializer = "new java.util.StringJoiner(" + StreamEx.of(collectorArgs).map(PsiElement::getText).joining(",") + ")";
|
||||
return new AccumulatedTerminalOperation("joiner", "java.util.StringJoiner", initializer,
|
||||
"{acc}.add({item});", "{acc}.toString()");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Contract("null -> null")
|
||||
static PsiType getOptionalElementType(PsiType type) {
|
||||
if(!(type instanceof PsiClassType)) return null;
|
||||
PsiClass aClass = ((PsiClassType)type).resolve();
|
||||
if(aClass == null) return null;
|
||||
if("java.util.OptionalInt".equals(aClass.getQualifiedName())) {
|
||||
return PsiType.INT;
|
||||
}
|
||||
if("java.util.OptionalLong".equals(aClass.getQualifiedName())) {
|
||||
return PsiType.LONG;
|
||||
}
|
||||
if("java.util.OptionalDouble".equals(aClass.getQualifiedName())) {
|
||||
return PsiType.DOUBLE;
|
||||
}
|
||||
if(!CommonClassNames.JAVA_UTIL_OPTIONAL.equals(aClass.getQualifiedName())) return null;
|
||||
PsiType[] parameters = ((PsiClassType)type).getParameters();
|
||||
if(parameters.length != 1) return null;
|
||||
PsiType streamType = parameters[0];
|
||||
if(streamType instanceof PsiCapturedWildcardType) {
|
||||
streamType = ((PsiCapturedWildcardType)streamType).getUpperBound();
|
||||
}
|
||||
return streamType;
|
||||
}
|
||||
|
||||
static class ReduceTerminalOperation extends TerminalOperation {
|
||||
private PsiExpression myIdentity;
|
||||
private String myType;
|
||||
private FunctionHelper myUpdater;
|
||||
|
||||
public ReduceTerminalOperation(PsiExpression identity, FunctionHelper updater, String type) {
|
||||
myIdentity = identity;
|
||||
myType = type;
|
||||
myUpdater = updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
FunctionHelper.processUsedNames(myIdentity, usedNameConsumer);
|
||||
myUpdater.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
String accumulator = context.declareResult("acc", myType, myIdentity.getText());
|
||||
myUpdater.transform(context, accumulator, inVar.getName());
|
||||
return accumulator + "=" + myUpdater.getText() + ";";
|
||||
}
|
||||
}
|
||||
|
||||
static class ReduceToOptionalTerminalOperation extends TerminalOperation {
|
||||
private String myType;
|
||||
private FunctionHelper myUpdater;
|
||||
|
||||
public ReduceToOptionalTerminalOperation(FunctionHelper updater, String type) {
|
||||
myType = type;
|
||||
myUpdater = updater;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myUpdater.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
String seen = context.declare("seen", "boolean", "false");
|
||||
String accumulator = context.declareResult("acc", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null");
|
||||
myUpdater.transform(context, accumulator, inVar.getName());
|
||||
String optionalClass = getOptionalClass(myType);
|
||||
context.setFinisher("(" + seen + "?" + optionalClass + ".of(" + accumulator + "):" + optionalClass + ".empty())");
|
||||
return "if(!" + seen + ") {\n" +
|
||||
seen + "=true;\n" +
|
||||
accumulator + "=" + inVar + ";\n" +
|
||||
"} else {\n" +
|
||||
accumulator + "=" + myUpdater.getText() + ";\n" +
|
||||
"}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class AverageTerminalOperation extends TerminalOperation {
|
||||
private boolean myDoubleAccumulator;
|
||||
|
||||
public AverageTerminalOperation(boolean doubleAccumulator) {
|
||||
myDoubleAccumulator = doubleAccumulator;
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
String sum = context.declareResult("sum", myDoubleAccumulator ? "double" : "long", "0");
|
||||
String count = context.declare("count", "long", "0");
|
||||
context.setFinisher("("+count+"==0?java.util.OptionalDouble.empty():"
|
||||
+"java.util.OptionalDouble.of("+(myDoubleAccumulator?"":"(double)")+sum+"/"+count+"))");
|
||||
return sum + "+=" + inVar + ";\n" + count + "++;\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class ToPrimitiveArrayTerminalOperation extends TerminalOperation {
|
||||
private String myType;
|
||||
|
||||
ToPrimitiveArrayTerminalOperation(String type) {
|
||||
myType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
String arr = context.declareResult("arr", myType + "[]", "new " + myType + "[10]");
|
||||
String count = context.declare("count", "int", "0");
|
||||
context.setFinisher("java.util.Arrays.copyOfRange("+arr+",0,"+count+")");
|
||||
return "if(" + arr + ".length==" + count + ") " + arr + "=java.util.Arrays.copyOf(" + arr + "," + count + "*2);\n" +
|
||||
arr + "[" + count + "++]=" + inVar + ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class FindTerminalOperation extends TerminalOperation {
|
||||
private String myType;
|
||||
|
||||
public FindTerminalOperation(String type) {
|
||||
myType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
int pos = myType.indexOf('<');
|
||||
String optType = pos == -1 ? myType : myType.substring(0, pos);
|
||||
return context.assignAndBreak("found", myType, optType + ".of(" + inVar + ")", optType + ".empty()");
|
||||
}
|
||||
}
|
||||
|
||||
static class MatchTerminalOperation extends TerminalOperation {
|
||||
private final FunctionHelper myFn;
|
||||
private final String myName;
|
||||
private final boolean myDefaultValue, myNegatePredicate;
|
||||
|
||||
public MatchTerminalOperation(FunctionHelper fn, String name) {
|
||||
myFn = fn;
|
||||
switch(name) {
|
||||
case "anyMatch":
|
||||
myName = "found";
|
||||
myDefaultValue = false;
|
||||
myNegatePredicate = false;
|
||||
break;
|
||||
case "allMatch":
|
||||
myName = "allMatch";
|
||||
myDefaultValue = true;
|
||||
myNegatePredicate = true;
|
||||
break;
|
||||
case "noneMatch":
|
||||
myName = "noneMatch";
|
||||
myDefaultValue = true;
|
||||
myNegatePredicate = false;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myFn.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestNames(StreamVariable inVar, StreamVariable outVar) {
|
||||
myFn.suggestVariableName(inVar, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
myFn.transform(context, inVar.getName());
|
||||
String expression = myNegatePredicate ? BoolUtils.getNegatedExpressionText(myFn.getExpression()) : myFn.getText();
|
||||
return "if(" + expression + ") {\n" +
|
||||
context.assignAndBreak(myName, PsiType.BOOLEAN.getCanonicalText(), String.valueOf(!myDefaultValue), String.valueOf(myDefaultValue)) +
|
||||
"}\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class AccumulatedTerminalOperation extends TerminalOperation {
|
||||
private String myAccName;
|
||||
private String myAccType;
|
||||
private String myAccInitializer;
|
||||
private String myUpdateTemplate;
|
||||
private String myFinisherTemplate;
|
||||
|
||||
/**
|
||||
* @param accName desired name for accumulator variable
|
||||
* @param accType type of accumulator variable
|
||||
* @param accInitializer initializer for accumulator variable
|
||||
* @param updateTemplate template to update accumulator. May contain {@code {acc}} - reference to accumulator variable
|
||||
* and {@code {item}} - reference to stream element.
|
||||
* @param finisherTemplate template to final result. May contain {@code {acc}} - reference to accumulator variable.
|
||||
* By default it's {@code "{acc}"}
|
||||
*/
|
||||
AccumulatedTerminalOperation(String accName, String accType, String accInitializer, String updateTemplate, String finisherTemplate) {
|
||||
myAccName = accName;
|
||||
myAccType = accType;
|
||||
myAccInitializer = accInitializer;
|
||||
myUpdateTemplate = updateTemplate;
|
||||
myFinisherTemplate = finisherTemplate;
|
||||
}
|
||||
|
||||
AccumulatedTerminalOperation(String accName, String accType, String accInitializer, String updateTemplate) {
|
||||
this(accName, accType, accInitializer, updateTemplate, "{acc}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
String varName = context.declareResult(myAccName, myAccType, myAccInitializer);
|
||||
context.setFinisher(myFinisherTemplate.replace("{acc}", varName));
|
||||
return myUpdateTemplate.replace("{item}", inVar.getName()).replace("{acc}", varName);
|
||||
}
|
||||
|
||||
public static AccumulatedTerminalOperation toCollection(PsiType collectionType, String implementationType, String varName) {
|
||||
return new AccumulatedTerminalOperation(varName, collectionType.getCanonicalText(), "new " + implementationType + "<>()",
|
||||
"{acc}.add({item});");
|
||||
}
|
||||
}
|
||||
|
||||
static class ToCollectionTerminalOperation extends TerminalOperation {
|
||||
private final String myType;
|
||||
private final FunctionHelper myFn;
|
||||
|
||||
public ToCollectionTerminalOperation(FunctionHelper fn, PsiType callType) {
|
||||
myFn = fn;
|
||||
myType = callType.getCanonicalText();
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myFn.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
// TODO: remove redundant type arguments
|
||||
myFn.transform(context);
|
||||
String collection = context.declareResult("collection", myType, myFn.getText());
|
||||
return collection+".add("+inVar+");\n";
|
||||
}
|
||||
}
|
||||
|
||||
static class ForEachTerminalOperation extends TerminalOperation {
|
||||
private FunctionHelper myFn;
|
||||
|
||||
public ForEachTerminalOperation(FunctionHelper fn) {
|
||||
myFn = fn;
|
||||
}
|
||||
|
||||
@Override
|
||||
void registerUsedNames(Consumer<String> usedNameConsumer) {
|
||||
myFn.registerUsedNames(usedNameConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
myFn.transform(context, inVar.getName());
|
||||
return myFn.getText()+";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static boolean test(List<List<String>> list) {
|
||||
for (List<String> x : list) {
|
||||
if (x != null) {
|
||||
for (String s : x) {
|
||||
if (!s.startsWith("a")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static void test(List<List<String>> list) {
|
||||
boolean allMatch = true;
|
||||
OUTER:
|
||||
for (List<String> x : list) {
|
||||
if (x != null) {
|
||||
for (String s : x) {
|
||||
if (!s.startsWith("a")) {
|
||||
allMatch = false;
|
||||
break OUTER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(allMatch) {
|
||||
System.out.println("ok");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static boolean test(List<List<String>> list) {
|
||||
for (List<String> x : list) {
|
||||
if (x != null) {
|
||||
for (String s : x) {
|
||||
if (s.startsWith("a")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class Main {
|
||||
private static long test() {
|
||||
long count = 0;
|
||||
Set<Integer> uniqueValues = new HashSet<>();
|
||||
long toSkip = 1;
|
||||
for (Integer integer : new Integer[]{1, 2, 3, 2, 3}) {
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
if (uniqueValues.add(integer)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalDouble test(long... numbers) {
|
||||
double sum = 0;
|
||||
long count = 0;
|
||||
for (long x : numbers) {
|
||||
if (x > 0) {
|
||||
double v = x;
|
||||
sum += v;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (count == 0 ? OptionalDouble.empty() : OptionalDouble.of(sum / count));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(-1,-2,-3, Long.MAX_VALUE, Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalDouble test(int... numbers) {
|
||||
long sum = 0;
|
||||
long count = 0;
|
||||
for (int x : numbers) {
|
||||
if (x > 0) {
|
||||
sum += x;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (count == 0 ? OptionalDouble.empty() : OptionalDouble.of((double) sum / count));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(-1,-2,-3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalDouble test(long... numbers) {
|
||||
long sum = 0;
|
||||
long count = 0;
|
||||
for (long x : numbers) {
|
||||
if (x > 0) {
|
||||
sum += x;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return (count == 0 ? OptionalDouble.empty() : OptionalDouble.of((double) sum / count));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(-1,-2,-3, Long.MAX_VALUE, Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static List<Integer> test(int[] numbers) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int number : numbers) {
|
||||
Integer integer = number;
|
||||
list.add(integer);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(new int[] {1,2,3}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static Optional<String> test(List<String> list) {
|
||||
boolean seen = false;
|
||||
String acc = null;
|
||||
for (String s : list) {
|
||||
if (!seen) {
|
||||
seen = true;
|
||||
acc = s;
|
||||
} else {
|
||||
acc = acc + s;
|
||||
}
|
||||
}
|
||||
return (seen ? Optional.of(acc) : Optional.empty());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static String test(List<String> list) {
|
||||
String acc = "";
|
||||
for (String s : list) {
|
||||
acc = acc + s;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public void test(List<String> list) {
|
||||
long count = 0;
|
||||
for (String s : list) {
|
||||
count++;
|
||||
}
|
||||
long x = count;
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
static class Count {
|
||||
}
|
||||
|
||||
public long test(List<Count> count) {
|
||||
long result = 0;
|
||||
for (Count count1 : count) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public long test(List<String> list) {
|
||||
if(!list.isEmpty()) {
|
||||
long count = 0;
|
||||
for (String s : list) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public long test(List<String> list) {
|
||||
long count = 0;
|
||||
for (String s : list) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Main {
|
||||
public long test(List<String> list) {
|
||||
long count = 0;
|
||||
Set<String> uniqueValues = new HashSet<>();
|
||||
for (String s : list) {
|
||||
if (uniqueValues.add(s)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static List<Object> test(List<? extends Number> numbers) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
Set<Number> uniqueValues = new HashSet<>();
|
||||
for (Number number : numbers) {
|
||||
if (uniqueValues.add(number)) {
|
||||
list.add(number);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList(1,2,3,5,3,2,2,2,1,1,4,3)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Main {
|
||||
private static long countInRange(int... input) {
|
||||
long count = 0;
|
||||
for (int x : input) {
|
||||
if (x > 0) {
|
||||
if (x < 10) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(countInRange(1, 2, 3, -1, -2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Main {
|
||||
private static long countInRange(int... input) {
|
||||
int x = 1;
|
||||
long count = 0;
|
||||
for (int y : input) {
|
||||
if (y > 0) {
|
||||
if (y < 10) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(countInRange(1, 2, 3, -1, -2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Main {
|
||||
private static long countInRange(int... input) {
|
||||
int x = 1;
|
||||
int y = 2;
|
||||
long count = 0;
|
||||
for (int i : input) {
|
||||
if (i > 0) {
|
||||
if (i < 10) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(countInRange(1, 2, 3, -1, -2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Main {
|
||||
private static long countInRange(int... input) {
|
||||
int x = 1;
|
||||
int y = 2;
|
||||
int i = 3;
|
||||
long count = 0;
|
||||
for (int x1 : input) {
|
||||
if (x1 > 0) {
|
||||
if (x1 < 10) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(countInRange(1, 2, 3, -1, -2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Main {
|
||||
private static long countInRange(int... input) {
|
||||
int x = 1;
|
||||
int i = 3;
|
||||
long result = 0;
|
||||
for (int count : input) {
|
||||
if (count > 0) {
|
||||
if (count < 10) {
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(countInRange(1, 2, 3, -1, -2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
|
||||
public class Main {
|
||||
public static LongSummaryStatistics test(List<List<String>> list) {
|
||||
LongSummaryStatistics stat = new LongSummaryStatistics();
|
||||
for (List<String> a : list) {
|
||||
if (a != null) {
|
||||
for (String s : a) {
|
||||
long l = s.length();
|
||||
stat.accept(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList(null, Arrays.asList("aaa", "b", "cc", "dddd"), Arrays.asList("gggg"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static List<Integer> getPositiveDoubled(int... input) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int x : input) {
|
||||
if (x > 0) {
|
||||
Integer integer = x * 2;
|
||||
list.add(integer);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(getPositiveDoubled(1, 2, 3, -1, -2));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static Optional<String> test(List<List<String>> list) {
|
||||
for (List<String> x : list) {
|
||||
if (x != null) {
|
||||
for (String s : x) {
|
||||
return Optional.of(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static Optional<String> test(List<List<String>> list) {
|
||||
OUTER:
|
||||
for(int i=0; i<10; i++) {
|
||||
Optional<String> found = Optional.empty();
|
||||
OUTER1:
|
||||
for (List<String> x : list) {
|
||||
if (x != null) {
|
||||
for (String s : x) {
|
||||
found = Optional.of(s);
|
||||
break OUTER1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found.orElse("");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static OptionalInt test() {
|
||||
for (int x = 0; x < 100; x++) {
|
||||
if (x > 50) {
|
||||
return OptionalInt.of(x);
|
||||
}
|
||||
}
|
||||
return OptionalInt.empty();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static int test() {
|
||||
OptionalInt found = OptionalInt.empty();
|
||||
for (int x = 0; x < 100; x++) {
|
||||
if (x > 50) {
|
||||
found = OptionalInt.of(x);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found.orElse(0);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static Optional<String> test(List<String> list) {
|
||||
for (String s : list) {
|
||||
return Optional.of(s);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
private static long test(List<List<String>> nested) {
|
||||
long count = 0;
|
||||
for (List<String> names : nested) {
|
||||
Set<String> uniqueValues = new HashSet<>();
|
||||
for (String name : names) {
|
||||
if (uniqueValues.add(name)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList("a"), asList(null, "bb", "ccc"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 50;
|
||||
OUTER:
|
||||
for (int x = 0; x < 100; x++) {
|
||||
long limitInner = x / 2;
|
||||
for (int i = 0; i < x; i++) {
|
||||
if (limitInner-- == 0) break;
|
||||
if (limit-- == 0) break OUTER;
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 500;
|
||||
OUTER:
|
||||
for (int x = 0; x < 100; x++) {
|
||||
long limitInner = x / 2;
|
||||
INNER:
|
||||
for (int y = 0; y < x; y++) {
|
||||
long limit1 = 10;
|
||||
int bound = y + 100;
|
||||
for (int i = y; i < bound; i++) {
|
||||
if (limit1-- == 0) break;
|
||||
if (limitInner-- == 0) break INNER;
|
||||
if (limit-- == 0) break OUTER;
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 500;
|
||||
OUTER:
|
||||
for (int x = 0; x < 100; x++) {
|
||||
long limitInner = x / 2;
|
||||
INNER:
|
||||
for (int y = 0; y < x; y++) {
|
||||
long limit1 = 10;
|
||||
int boundInner = y + 100;
|
||||
INNER1:
|
||||
for (int z = y; z < boundInner; z++) {
|
||||
int bound = z + 2;
|
||||
for (int i = z; i < bound; i++) {
|
||||
if (limit1-- == 0) break INNER1;
|
||||
if (limitInner-- == 0) break INNER;
|
||||
if (limit-- == 0) break OUTER;
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static long test(Map<String, List<String>> strings) {
|
||||
long count = 0;
|
||||
for (Map.Entry<String, List<String>> e : strings.entrySet()) {
|
||||
if (!e.getKey().isEmpty()) {
|
||||
String sInner = e.getKey();
|
||||
for (String s : e.getValue()) {
|
||||
if (sInner.equals(s)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("", Arrays.asList("", "a", "b"));
|
||||
map.put("a", Arrays.asList("", "a", "b", "a"));
|
||||
map.put("b", Arrays.asList("", "a", "b"));
|
||||
map.put("c", Arrays.asList("", "a", "b"));
|
||||
System.out.println(test(map));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
|
||||
public class Main {
|
||||
public static LongSummaryStatistics test(List<List<String>> list) {
|
||||
return list.stream().filter(a -> a != null).flatMapToLong(lst -> lst.stream().distinct().mapToLong(a -> a.length())).summa<caret>ryStatistics();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList(null, Arrays.asList("aaa", "b", "cc", "cc", "dddd"), Arrays.asList("cc", "b", "gggg"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test(List<List<List<String>>> list) {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (List<List<String>> l : list) {
|
||||
if (l != null) {
|
||||
for (List<String> lst : l) {
|
||||
if (lst != null) {
|
||||
for (String str : lst) {
|
||||
int i = str.length();
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(asList("a", "bbb", "ccc")), asList(), null, asList(asList("z")))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
|
||||
public class Main {
|
||||
public static LongSummaryStatistics test(List<List<String>> list) {
|
||||
LongSummaryStatistics stat = new LongSummaryStatistics();
|
||||
for (List<String> a : list) {
|
||||
if (a != null) {
|
||||
for (String s : a) {
|
||||
long l = s.length();
|
||||
stat.accept(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList(null, Arrays.asList("aaa", "b", "cc", "dddd"), Arrays.asList("gggg"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test(int... values) {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long toSkipOuter = 1;
|
||||
for (int x : values) {
|
||||
if (toSkipOuter > 0) {
|
||||
toSkipOuter--;
|
||||
continue;
|
||||
}
|
||||
if (x > 0) {
|
||||
long toSkip = x;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(1, 95, -2, 0, 97, 90));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test(int... values) {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long toSkip = 1;
|
||||
for (int x : values) {
|
||||
if (x > 0) {
|
||||
long toSkipInner = x;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (toSkipInner > 0) {
|
||||
toSkipInner--;
|
||||
continue;
|
||||
}
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(1, 95, -2, 0, 97, 90));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static void test(List<String> list) {
|
||||
for (String x : list) {
|
||||
if (x != null) {
|
||||
System.out.println(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test(Arrays.asList("a", "b", "xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Main {
|
||||
static Predicate<String> nonEmpty = s -> s != null && !s.isEmpty();
|
||||
|
||||
private static long test(List<String> strings) {
|
||||
long count = 0;
|
||||
for (String string : strings) {
|
||||
if (nonEmpty.test(string)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class Main {
|
||||
private static long test(List<Predicate<String>> predicates, List<String> strings) {
|
||||
long count = 0;
|
||||
for (Predicate<String> pred : predicates) {
|
||||
if (pred != null) {
|
||||
for (String string : strings) {
|
||||
if (pred.test(string)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(
|
||||
Arrays.asList(String::isEmpty, s -> s.length() > 3),
|
||||
Arrays.asList("", "a", "abcd", "xyz")
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 33;
|
||||
OUTER:
|
||||
while (true) {
|
||||
Integer x = 10;
|
||||
for (int i = 0; i < x; i++) {
|
||||
if (limit-- == 0) break OUTER;
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
public static Integer getInt() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 33;
|
||||
OUTER:
|
||||
while (true) {
|
||||
Integer x = Main.getInt();
|
||||
for (int i = 0; i < x; i++) {
|
||||
if (limit-- == 0) break OUTER;
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.DoubleSummaryStatistics;
|
||||
import java.util.Random;
|
||||
import java.util.stream.DoubleStream;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static DoubleSummaryStatistics test() {
|
||||
Random r = new Random();
|
||||
DoubleSummaryStatistics stat = new DoubleSummaryStatistics();
|
||||
for (int x = 0; x < 10; x++) {
|
||||
double x1 = x;
|
||||
long limit = (long) x1;
|
||||
while (true) {
|
||||
double v = r.nextDouble() * x1;
|
||||
if (limit-- == 0) break;
|
||||
stat.accept(v);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static void test(List<String> list) {
|
||||
boolean found = false;
|
||||
for (String x : list) {
|
||||
if (x != null) {
|
||||
if (x.startsWith("x")) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(found) {
|
||||
System.out.println("Ok!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test(Arrays.asList("a", "b", "xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (int i : new int[]{1, 2, 3}) {
|
||||
stat.accept(i);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (int i : new int[]{1, 2, 3}) {
|
||||
stat.accept(i);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 20;
|
||||
for (String x = ""; ; x = x + "a") {
|
||||
if (limit-- == 0) break;
|
||||
int i = x.length();
|
||||
stat.accept(i);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public static List<String> test() {
|
||||
List<String> list = new ArrayList<>();
|
||||
long limit = 20;
|
||||
for (String x = ""; ; x = x + "a") {
|
||||
if (limit-- == 0) break;
|
||||
list.add(x);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (int limit = 0; limit < 20; limit++) {
|
||||
long limitInner = limit;
|
||||
for (String x = ""; ; x = x + limit) {
|
||||
if (limitInner-- == 0) break;
|
||||
int i = x.length();
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
private static List<String> test() {
|
||||
List<String> list = new ArrayList<>();
|
||||
for (int x = 0; x < 20; x++) {
|
||||
Integer integer = x;
|
||||
long limit = integer;
|
||||
for (String str = ""; ; str = "a" + str) {
|
||||
if (limit-- == 0) break;
|
||||
list.add(str);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(String.join("|", test()).length());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (int x = 0; x < 20; x++) {
|
||||
if (x > 2) {
|
||||
long limit = x;
|
||||
for (String s = String.valueOf(x); ; s = s + x) {
|
||||
if (limit-- == 0) break;
|
||||
int i = s.length();
|
||||
stat.accept(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
public static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
long limit = 50;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (limit-- == 0) break;
|
||||
stat.accept(i);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static long countNonEmpty(List<String> input) {
|
||||
long count = 0;
|
||||
for (String str : input) {
|
||||
String s = str.trim();
|
||||
if (!s.isEmpty()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(countNonEmpty(Arrays.asList("a", "", "b", "", "")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static String getString() {
|
||||
return "abc";
|
||||
}
|
||||
|
||||
private static boolean test(List<String> strings) {
|
||||
String s = getString();
|
||||
for (String string : strings) {
|
||||
if (s.equals(string)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Main {
|
||||
private static void test(List<String> names) {
|
||||
for (String name : names) {
|
||||
if (Objects.nonNull(name)) {
|
||||
System.out.println(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test(Arrays.asList("a", "b", "xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static long test(Map<String, List<String>> strings) {
|
||||
long sum = 0;
|
||||
for (Map.Entry<String, List<String>> e : strings.entrySet()) {
|
||||
if (!e.getKey().isEmpty()) {
|
||||
long l = e.getValue().stream().filter(new Predicate<String>() {
|
||||
@Override
|
||||
public boolean test(String s) {
|
||||
return e.getKey().equals(s);
|
||||
}
|
||||
}).count();
|
||||
sum += l;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
boolean x = Stream.of(1, 2, 3).anyMatch(Objects::nonNull);
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("", Arrays.asList("", "a", "b"));
|
||||
map.put("a", Arrays.asList("", "a", "b", "a"));
|
||||
map.put("b", Arrays.asList("", "a", "b"));
|
||||
map.put("c", Arrays.asList("", "a", "b"));
|
||||
System.out.println(test(map));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static long test(Map<String, List<String>> strings) {
|
||||
long sum = 0;
|
||||
for (Map.Entry<String, List<String>> e : strings.entrySet()) {
|
||||
if (!e.getKey().isEmpty()) {
|
||||
long l = e.getValue().stream().filter(s -> e.getKey().equals(s)).count();
|
||||
sum += l;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
boolean x = Stream.of(1, 2, 3).anyMatch(Objects::nonNull);
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("", Arrays.asList("", "a", "b"));
|
||||
map.put("a", Arrays.asList("", "a", "b", "a"));
|
||||
map.put("b", Arrays.asList("", "a", "b"));
|
||||
map.put("c", Arrays.asList("", "a", "b"));
|
||||
System.out.println(test(map));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
|
||||
private static long test(Map<String, List<String>> strings) {
|
||||
long sum = 0;
|
||||
for (Map.Entry<String, List<String>> s : strings.entrySet()) {
|
||||
if (!s.getKey().isEmpty()) {
|
||||
long l = s.getValue().stream().filter(sx -> s.getKey().equals(sx)).count();
|
||||
sum += l;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
boolean x = Stream.of(1, 2, 3).anyMatch(Objects::nonNull);
|
||||
Map<String, List<String>> map = new HashMap<>();
|
||||
map.put("", Arrays.asList("", "a", "b"));
|
||||
map.put("a", Arrays.asList("", "a", "b", "a"));
|
||||
map.put("b", Arrays.asList("", "a", "b"));
|
||||
map.put("c", Arrays.asList("", "a", "b"));
|
||||
System.out.println(test(map));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static long test(List<String> list) {
|
||||
long count = 0;
|
||||
for (String l : list) {
|
||||
if (l != null) {
|
||||
(new Consumer<String>() {
|
||||
String lst = "hello";
|
||||
|
||||
public void accept(String lst) {
|
||||
System.out.println(this.lst + lst);
|
||||
}
|
||||
}).accept(l);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static long test(List<String> list) {
|
||||
long count = 0;
|
||||
for (String l : list) {
|
||||
if (l != null) {
|
||||
(new Consumer<String>() {
|
||||
String list = "hello";
|
||||
|
||||
public void accept(String list) {
|
||||
System.out.println(this.list + l);
|
||||
}
|
||||
}).accept(l);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static boolean test(List<List<String>> list) {
|
||||
for (List<String> x : list) {
|
||||
if (x != null) {
|
||||
for (String str : x) {
|
||||
if (str.startsWith("a")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class Main {
|
||||
private static String test(List<String> list) {
|
||||
if (list == null) return null;
|
||||
else {
|
||||
Optional<String> found = Optional.empty();
|
||||
for (String str : list) {
|
||||
if (str.contains("x")) {
|
||||
found = Optional.of(str);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("a", "b", "syz")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public static int test(List<String> list) {
|
||||
int sum = 0;
|
||||
for (String s : list) {
|
||||
System.out.println(s);
|
||||
int i = s.length();
|
||||
sum += i;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("aaa", "b", "cc", "dddd")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.LongSummaryStatistics;
|
||||
|
||||
public class Main {
|
||||
public static LongSummaryStatistics test(List<String> list) {
|
||||
LongSummaryStatistics stat = new LongSummaryStatistics();
|
||||
for (String s : list) {
|
||||
System.out.println(s);
|
||||
long l = s.length();
|
||||
stat.accept(l);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("aaa", "b", "cc", "dddd")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static long check(int start, int stop, double v) {
|
||||
long count = 0;
|
||||
for (int x = start; x < stop; x++) {
|
||||
double x1 = 1.0 / x;
|
||||
if (x1 < v) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(check(1, 100, 0.04));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static long check(int start, double val) {
|
||||
long count = 0;
|
||||
int bound = start * 200;
|
||||
for (int x = start; x <= bound; x++) {
|
||||
double v = 1.0 / x;
|
||||
if (v < val) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(check(2, 0.04));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static String test(List<String> list) {
|
||||
String acc = "";
|
||||
for (String s : list) {
|
||||
acc = acc + s;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static int test(List<String> list) {
|
||||
Integer acc = 0;
|
||||
for (String s : list) {
|
||||
acc = acc + s.length();
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static Integer test(List<Integer> numbers) {
|
||||
Integer acc = 0;
|
||||
for (Integer number : numbers) {
|
||||
acc = Math.max(acc, number);
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test(Arrays.asList("a", "b", "xyz"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalInt test() {
|
||||
boolean seen = false;
|
||||
int acc = 0;
|
||||
for (int i : new int[]{}) {
|
||||
if (!seen) {
|
||||
seen = true;
|
||||
acc = i;
|
||||
} else {
|
||||
acc = acc * i;
|
||||
}
|
||||
}
|
||||
return (seen ? OptionalInt.of(acc) : OptionalInt.empty());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
private static Optional<Integer> test(Integer... numbers) {
|
||||
boolean seen = false;
|
||||
Integer acc = null;
|
||||
for (Integer number : numbers) {
|
||||
if (!seen) {
|
||||
seen = true;
|
||||
acc = number;
|
||||
} else {
|
||||
acc = acc * number;
|
||||
}
|
||||
}
|
||||
return (seen ? Optional.of(acc) : Optional.empty());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(1,2,3,4));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
private static long test(List<?> list) {
|
||||
long count = 0;
|
||||
Set<Object> uniqueValues = new HashSet<>();
|
||||
long toSkip = list.size() / 2;
|
||||
for (Object o : list) {
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
if (uniqueValues.add(o)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList(1,2,3,3,2,1,1,2,3)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static String test(List<CharSequence> list) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Set<CharSequence> uniqueValues = new HashSet<>();
|
||||
long toSkip = 1;
|
||||
for (CharSequence charSequence : list) {
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
if (uniqueValues.add(charSequence)) {
|
||||
sb.append(charSequence);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("a", "b", "e", "c", "d", "e", "a")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static String test(List<CharSequence> list, String delimiter) {
|
||||
StringJoiner joiner = new StringJoiner(delimiter);
|
||||
long toSkip = 2;
|
||||
Set<CharSequence> uniqueValues = new HashSet<>();
|
||||
long toSkip1 = 1;
|
||||
for (CharSequence charSequence : list) {
|
||||
if (toSkip1 > 0) {
|
||||
toSkip1--;
|
||||
continue;
|
||||
}
|
||||
if (uniqueValues.add(charSequence)) {
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
joiner.add(charSequence);
|
||||
}
|
||||
}
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("a", "b", "e", "c", "d", "e", "a"), ";"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static String test(List<CharSequence> list, String delimiter) {
|
||||
StringJoiner joiner = new StringJoiner(delimiter, "<", ">");
|
||||
Set<CharSequence> uniqueValues = new HashSet<>();
|
||||
long toSkip = 1;
|
||||
for (CharSequence charSequence : list) {
|
||||
if (toSkip > 0) {
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
if (uniqueValues.add(charSequence)) {
|
||||
joiner.add(charSequence);
|
||||
}
|
||||
}
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(Arrays.asList("a", "b", "e", "c", "d", "e", "a"), ";"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
private static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (Integer i : new Integer[]{1, 2, 3}) {
|
||||
int i1 = i;
|
||||
stat.accept(i1);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
private static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (Number[] nums : Arrays.<Number[]>asList(new Integer[]{1, 2, 3})) {
|
||||
int i = (int) nums[0];
|
||||
stat.accept(i);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.IntSummaryStatistics;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Main {
|
||||
private static IntSummaryStatistics test() {
|
||||
IntSummaryStatistics stat = new IntSummaryStatistics();
|
||||
for (Supplier<Integer> sup : Arrays.<Supplier<Integer>>asList(() -> 1, () -> 2, () -> 3)) {
|
||||
int i = sup.get();
|
||||
stat.accept(i);
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static Integer[][] test(int[] numbers) {
|
||||
List<Integer[]> list = new ArrayList<>();
|
||||
for (int number : numbers) {
|
||||
Integer n = number;
|
||||
Integer[] integers = new Integer[]{n};
|
||||
list.add(integers);
|
||||
}
|
||||
return list.toArray(new Integer[0][]);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Arrays.asList(test(new int[] {1,2,3})));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static Number[] test(int[] numbers) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int number : numbers) {
|
||||
Integer integer = number;
|
||||
list.add(integer);
|
||||
}
|
||||
return list.toArray(new Integer[0]);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Arrays.asList(test(new int[] {1,2,3})));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static List<?>[] test(int[] numbers) {
|
||||
List<List<?>> list = new ArrayList<>();
|
||||
for (int number : numbers) {
|
||||
Integer n = number;
|
||||
List<Integer> integers = Collections.singletonList(n);
|
||||
list.add(integers);
|
||||
}
|
||||
return list.toArray(new List<?>[0]);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Arrays.asList(test(new int[] {1,2,3})));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
private static Object[] test(int[] numbers) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
for (int number : numbers) {
|
||||
Integer integer = number;
|
||||
list.add(integer);
|
||||
}
|
||||
return list.toArray();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Arrays.asList(test(new int[] {1,2,3})));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static TreeSet<Integer> test() {
|
||||
TreeSet<Integer> collection = new TreeSet<Integer>();
|
||||
for (int i : new int[]{4, 2, 1}) {
|
||||
Integer integer = i;
|
||||
collection.add(integer);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static int[] test() {
|
||||
int[] arr = new int[10];
|
||||
int count = 0;
|
||||
for (int x = -100; x < 100; x++) {
|
||||
if (x > 0) {
|
||||
if (arr.length == count) arr = Arrays.copyOf(arr, count * 2);
|
||||
arr[count++] = x;
|
||||
}
|
||||
}
|
||||
return Arrays.copyOfRange(arr, 0, count);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(Arrays.toString(test()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static boolean test(List<List<String>> list) {
|
||||
return list.stream().filter(x -> x != null).flatMap(x -> x.stream()).allMat<caret>ch(x -> x.startsWith("a"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static void test(List<List<String>> list) {
|
||||
if(list.stream().filter(x -> x != null).flatMap(x -> x.stream()).allMat<caret>ch(x -> x.startsWith("a"))) {
|
||||
System.out.println("ok");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static boolean test(List<List<String>> list) {
|
||||
return list.stream().filter(x -> x != null).flatMap(x -> x.stream()).anyMat<caret>ch(x -> x.startsWith("a"));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList(asList(), asList("a"), asList("b", "c"))));
|
||||
System.out.println(test(asList(asList(), asList("d"), asList("b", "c"))));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Main {
|
||||
private static long test() {
|
||||
return Arrays.stream(new Integer[] {1,2,3,2,3}).skip(1).distinct().cou<caret>nt();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalDouble test(long... numbers) {
|
||||
return LongStream.of(numbers).filter(x -> x > 0).asDoubleStream().avera<caret>ge();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(-1,-2,-3, Long.MAX_VALUE, Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalDouble test(int... numbers) {
|
||||
return IntStream.of(numbers).filter(x -> x > 0).aver<caret>age();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(-1,-2,-3));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
public class Main {
|
||||
private static OptionalDouble test(long... numbers) {
|
||||
return LongStream.of(numbers).filter(x -> x > 0).avera<caret>ge();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(-1,-2,-3, Long.MAX_VALUE, Long.MAX_VALUE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
private static List<Integer> test(int[] numbers) {
|
||||
return Arrays.stream(numbers).boxed().c<caret>ollect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(new int[] {1,2,3}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// "Replace Stream API chain with loop" "true"
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
public class Main {
|
||||
public static Optional<String> test(List<String> list) {
|
||||
return list.stream().coll<caret>ect(Collectors.reducing((a, b) -> a+b));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(test(asList("a", "b", "c")));
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user