From b7a423d0012404afad0ca0997dee7b6d031379ca Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Fri, 2 Sep 2016 17:50:00 +0700 Subject: [PATCH] IDEA-160707 Stream API migration: support object arrays --- .../StreamApiMigrationInspection.java | 169 +++++++++++------- .../streamApiMigration/afterArrayAddAll.java | 12 ++ .../afterArrayFilterCollect.java | 11 ++ .../afterFlatten2DArray.java | 12 ++ .../afterFlatten2DArrayPrimitive.java | 16 ++ .../streamApiMigration/beforeArrayAddAll.java | 12 ++ .../beforeArrayFilterCollect.java | 14 ++ .../beforeFlatten2DArray.java | 17 ++ .../beforeFlatten2DArrayPrimitive.java | 17 ++ .../beforePrimitiveArray.java | 10 ++ 10 files changed, 221 insertions(+), 69 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayAddAll.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayFilterCollect.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArray.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArrayPrimitive.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayAddAll.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayFilterCollect.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArray.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArrayPrimitive.java create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArray.java diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java index 9bce292b0b00..f344d9429c58 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/StreamApiMigrationInspection.java @@ -101,51 +101,62 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo if (iteratedValue != null && body != null) { final PsiType iteratedValueType = iteratedValue.getType(); final PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType); - final PsiClass collectionClass = JavaPsiFacade.getInstance(body.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope()); - if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) { - try { - final ControlFlow controlFlow = ControlFlowFactory.getInstance(holder.getProject()) - .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); - int startOffset = controlFlow.getStartOffset(body); - int endOffset = controlFlow.getEndOffset(body); - final Collection exitPoints = ControlFlowUtil - .findExitPointsAndStatements(controlFlow, startOffset, endOffset, new IntArrayList(), PsiContinueStatement.class, - PsiBreakStatement.class, PsiReturnStatement.class, PsiThrowStatement.class); - if (exitPoints.isEmpty()) { - - final List usedVariables = ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset); - for (PsiVariable variable : usedVariables) { - if (!HighlightControlFlowUtil.isEffectivelyFinal(variable, body, null)) { - return; - } + PsiClass collectionClass = null; + final boolean isArray; + if(iteratedValueType instanceof PsiArrayType) { + // Do not handle primitive types now + if(((PsiArrayType)iteratedValueType).getComponentType() instanceof PsiPrimitiveType) return; + isArray = true; + } else { + collectionClass = JavaPsiFacade.getInstance(body.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, statement.getResolveScope()); + if (collectionClass != null && InheritanceUtil.isInheritorOrSelf(iteratorClass, collectionClass, true)) { + isArray = false; + } else return; + } + try { + final ControlFlow controlFlow = ControlFlowFactory.getInstance(holder.getProject()) + .getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance()); + int startOffset = controlFlow.getStartOffset(body); + int endOffset = controlFlow.getEndOffset(body); + final Collection exitPoints = ControlFlowUtil + .findExitPointsAndStatements(controlFlow, startOffset, endOffset, new IntArrayList(), PsiContinueStatement.class, + PsiBreakStatement.class, PsiReturnStatement.class, PsiThrowStatement.class); + if (exitPoints.isEmpty()) { + + final List usedVariables = ControlFlowUtil.getUsedVariables(controlFlow, startOffset, endOffset); + for (PsiVariable variable : usedVariables) { + if (!HighlightControlFlowUtil.isEffectivelyFinal(variable, body, null)) { + return; } + } - if (ExceptionUtil.getThrownCheckedExceptions(new PsiElement[] {body}).isEmpty()) { - TerminalBlock tb = TerminalBlock.from(statement.getIterationParameter(), body); - List operations = tb.extractOperations(); + if (ExceptionUtil.getThrownCheckedExceptions(new PsiElement[]{body}).isEmpty()) { + TerminalBlock tb = TerminalBlock.from(statement.getIterationParameter(), body); + List operations = tb.extractOperations(); - if (!isRawSubstitution(iteratedValueType, collectionClass) && isCollectCall(tb, operations)) { - boolean addAll = operations.isEmpty() && isAddAllCall(tb); - holder.registerProblem(iteratedValue, "Can be replaced with " + (addAll ? "addAll call" : "collect call"), - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, - addAll ? new ReplaceWithAddAllFix() : new ReplaceWithCollectFix()); - } - else if (REPLACE_TRIVIAL_FOREACH || !operations.isEmpty() || !isTrivial(body, statement.getIterationParameter())) { - final List fixes = new ArrayList<>(); - fixes.add(new ReplaceWithForeachCallFix("forEach")); - if (!operations.isEmpty()) { - //for .stream() - fixes.add(new ReplaceWithForeachCallFix("forEachOrdered")); - } - holder.registerProblem(iteratedValue, "Can be replaced with foreach call", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, - fixes.toArray(new LocalQuickFix[fixes.size()])); + if ((isArray || !isRawSubstitution(iteratedValueType, collectionClass)) && isCollectCall(tb, operations)) { + boolean addAll = operations.isEmpty() && isAddAllCall(tb); + holder.registerProblem(iteratedValue, "Can be replaced with " + (addAll ? "addAll call" : "collect call"), + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + addAll ? new ReplaceWithAddAllFix() : new ReplaceWithCollectFix()); + } + // do not replace for(T e : arr) {} with Arrays.stream(arr).forEach(e -> {}) even if flag is set + else if (!operations.isEmpty() || + (!isArray && (REPLACE_TRIVIAL_FOREACH || !isTrivial(body, statement.getIterationParameter())))) { + final List fixes = new ArrayList<>(); + fixes.add(new ReplaceWithForeachCallFix("forEach")); + if (!operations.isEmpty()) { + //for .stream() + fixes.add(new ReplaceWithForeachCallFix("forEachOrdered")); } + holder.registerProblem(iteratedValue, "Can be replaced with foreach call", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + fixes.toArray(new LocalQuickFix[fixes.size()])); } } } - catch (AnalysisCanceledException ignored) { - } + } + catch (AnalysisCanceledException ignored) { } } } @@ -273,8 +284,8 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return ContainerUtil.find(method.getThrowsList().getReferencedTypes(), type -> !ExceptionUtil.isUncheckedException(type)) != null; } - private static boolean isIdentityMapping(PsiVariable parameter, PsiExpression mapperCall) { - return mapperCall instanceof PsiReferenceExpression && ((PsiReferenceExpression)mapperCall).resolve() == parameter; + private static boolean isIdentityMapping(PsiVariable variable, PsiExpression mapperCall) { + return mapperCall instanceof PsiReferenceExpression && ((PsiReferenceExpression)mapperCall).resolve() == variable; } private static class ReplaceWithForeachCallFix implements LocalQuickFix { @@ -311,11 +322,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo TerminalBlock tb = TerminalBlock.from(parameter, body); List intermediateOps = tb.extractOperationReplacements(elementFactory); - StringBuilder buffer = new StringBuilder(getIteratedValueText(iteratedValue)); - if (!intermediateOps.isEmpty()) { - buffer.append(".stream()"); - intermediateOps.forEach(buffer::append); - } + StringBuilder buffer = generateStream(iteratedValue, intermediateOps); PsiElement block = tb.convertToElement(elementFactory); buffer.append(".").append(myForEachMethodName).append("("); @@ -342,13 +349,13 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } - private static String createForEachFunctionalExpressionText(Project project, PsiElement block, PsiVariable parameter) { + private static String createForEachFunctionalExpressionText(Project project, PsiElement block, PsiVariable variable) { final PsiCallExpression callExpression = LambdaCanBeMethodReferenceInspection.extractMethodCallFromBlock(block); if (callExpression != null) { - final PsiClassType functionalType = createDefaultConsumerType(project, parameter); + final PsiClassType functionalType = createDefaultConsumerType(project, variable); String methodReferenceText = null; - if(parameter instanceof PsiParameter) { - final PsiParameter[] parameters = {(PsiParameter)parameter}; + if(variable instanceof PsiParameter) { + final PsiParameter[] parameters = {(PsiParameter)variable}; methodReferenceText = LambdaCanBeMethodReferenceInspection.convertToMethodReference(block, parameters, functionalType, null); } @@ -356,7 +363,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo return methodReferenceText; } } - return parameter.getName() + " -> " + wrapInBlock(block); + return variable.getName() + " -> " + wrapInBlock(block); } private static String wrapInBlock(PsiElement block) { @@ -414,6 +421,7 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo PsiStatement body = foreachStatement.getBody(); final PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (body != null && iteratedValue != null) { + final PsiType iteratedValueType = iteratedValue.getType(); final PsiParameter parameter = foreachStatement.getIterationParameter(); TerminalBlock tb = TerminalBlock.from(parameter, body); List intermediateOps = tb.extractOperationReplacements(elementFactory); @@ -425,15 +433,15 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo restoreComments(foreachStatement, body); final PsiExpression qualifierExpression = methodCallExpression.getMethodExpression().getQualifierExpression(); final String qualifierText = qualifierExpression != null ? qualifierExpression.getText() : ""; - final String callText = StringUtil.getQualifiedName(qualifierText, "addAll(" + getIteratedValueText(iteratedValue) + ");"); + final String collectionText = iteratedValueType instanceof PsiArrayType ? "java.util.Arrays.asList("+iteratedValue.getText()+")" : + getIteratedValueText(iteratedValue); + final String callText = StringUtil.getQualifiedName(qualifierText, "addAll(" + collectionText + ");"); PsiElement result = foreachStatement.replace(elementFactory.createStatementFromText(callText, foreachStatement)); reformatWhenNeeded(project, result); return; } - final StringBuilder builder = new StringBuilder(getIteratedValueText(iteratedValue) + ".stream()"); - - intermediateOps.forEach(builder::append); - builder.append(createMapperFunctionalExpressionText(tb.getVariable(), methodCallExpression.getArgumentList().getExpressions()[0])); + intermediateOps.add(createMapperFunctionalExpressionText(tb.getVariable(), methodCallExpression.getArgumentList().getExpressions()[0])); + final StringBuilder builder = generateStream(iteratedValue, intermediateOps); builder.append(".collect(java.util.stream.Collectors."); PsiElement result = null; @@ -650,6 +658,9 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo final PsiType iteratedValueType = iteratedValue.getType(); Operation op = null; if(iteratedValueType instanceof PsiArrayType) { + // do not handle flatMapToPrimitive + if (((PsiArrayType)iteratedValueType).getComponentType() instanceof PsiPrimitiveType) + return null; op = new ArrayFlatMapOp(iteratedValue, myVariable); } else { final PsiClass iteratorClass = PsiUtil.resolveClassInClassTypeOnly(iteratedValueType); @@ -680,15 +691,18 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo PsiElement element = elements[0]; if(element instanceof PsiLocalVariable) { PsiLocalVariable declaredVar = (PsiLocalVariable)element; - PsiExpression initializer = declaredVar.getInitializer(); - if (initializer != null && - ReferencesSearch.search(myVariable, new LocalSearchScope(Arrays.copyOfRange(myStatements, myFrom + 1, myTo))) - .findFirst() == null) { - MapOp op = new MapOp(initializer, myVariable); - myVariable = declaredVar; - myFrom++; - flatten(); - return op; + // do not handle mapToPrimitive + if(!(declaredVar.getType() instanceof PsiPrimitiveType)) { + PsiExpression initializer = declaredVar.getInitializer(); + if (initializer != null && + ReferencesSearch.search(myVariable, new LocalSearchScope(Arrays.copyOfRange(myStatements, myFrom + 1, myTo))) + .findFirst() == null) { + MapOp op = new MapOp(initializer, myVariable); + myVariable = declaredVar; + myFrom++; + flatten(); + return op; + } } } } @@ -754,12 +768,12 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } - private static String compoundLambdaOrMethodReference(PsiVariable parameter, + private static String compoundLambdaOrMethodReference(PsiVariable variable, PsiExpression expression, String samQualifiedName, PsiType[] samParamTypes) { String result = ""; - final Project project = parameter.getProject(); + final Project project = variable.getProject(); final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); final PsiClass functionClass = psiFacade.findClass(samQualifiedName, GlobalSearchScope.allScope(project)); for (int i = 0; i < samParamTypes.length; i++) { @@ -769,15 +783,15 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } final PsiClassType functionalInterfaceType = functionClass != null ? psiFacade.getElementFactory().createType(functionClass, samParamTypes) : null; String methodReferenceText = null; - if(parameter instanceof PsiParameter) { - final PsiParameter[] parameters = {(PsiParameter)parameter}; + if(variable instanceof PsiParameter) { + final PsiParameter[] parameters = {(PsiParameter)variable}; methodReferenceText = LambdaCanBeMethodReferenceInspection.convertToMethodReference(expression, parameters, functionalInterfaceType, null); } if (methodReferenceText != null) { LOG.assertTrue(functionalInterfaceType != null); result += "(" + functionalInterfaceType.getCanonicalText() + ")" + methodReferenceText; } else { - result += parameter.getName() + " -> " + expression.getText(); + result += variable.getName() + " -> " + expression.getText(); } return result; } @@ -803,6 +817,23 @@ public class StreamApiMigrationInspection extends BaseJavaBatchLocalInspectionTo } } + @NotNull + private static StringBuilder generateStream(PsiExpression iteratedValue, List intermediateOps) { + StringBuilder buffer = new StringBuilder(); + final PsiType iteratedValueType = iteratedValue.getType(); + if (iteratedValueType instanceof PsiArrayType) { + buffer.append("java.util.Arrays.stream(").append(iteratedValue.getText()).append(")"); + } + else { + buffer.append(getIteratedValueText(iteratedValue)); + if (!intermediateOps.isEmpty()) { + buffer.append(".stream()"); + } + } + intermediateOps.forEach(buffer::append); + return buffer; + } + private static String getIteratedValueText(PsiExpression iteratedValue) { return iteratedValue instanceof PsiCallExpression || iteratedValue instanceof PsiReferenceExpression || diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayAddAll.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayAddAll.java new file mode 100644 index 000000000000..c7ea723552fb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayAddAll.java @@ -0,0 +1,12 @@ +// "Replace with addAll" "true" +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Main { + public void test(Integer[] arr) { + List result = new ArrayList<>(); + result.add(1); + result.addAll(Arrays.asList(arr)); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayFilterCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayFilterCollect.java new file mode 100644 index 000000000000..883fd7326822 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterArrayFilterCollect.java @@ -0,0 +1,11 @@ +// "Replace with collect" "true" +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public void test(Integer[] arr) { + List result = Arrays.stream(arr).filter(x -> x > 5).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArray.java new file mode 100644 index 000000000000..c4093c0cd3c7 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArray.java @@ -0,0 +1,12 @@ +// "Replace with collect" "true" +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class Main { + public List test(String[][] arr) { + List result = Arrays.stream(arr).filter(subArr -> subArr != null).flatMap(Arrays::stream).collect(Collectors.toList()); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArrayPrimitive.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArrayPrimitive.java new file mode 100644 index 000000000000..b922369f9b24 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/afterFlatten2DArrayPrimitive.java @@ -0,0 +1,16 @@ +// "Replace with forEach" "true" +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Main { + public List test(int[][] arr) { + List result = new ArrayList<>(); + Arrays.stream(arr).filter(subArr -> subArr != null).forEach(subArr -> { + for (int str : subArr) { + result.add(str); + } + }); + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayAddAll.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayAddAll.java new file mode 100644 index 000000000000..61438f6482f6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayAddAll.java @@ -0,0 +1,12 @@ +// "Replace with addAll" "true" +import java.util.ArrayList; +import java.util.List; + +public class Main { + public void test(Integer[] arr) { + List result = new ArrayList<>(); + result.add(1); + for(Integer i : arr) + result.add(i); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayFilterCollect.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayFilterCollect.java new file mode 100644 index 000000000000..e8a505c2a0e3 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeArrayFilterCollect.java @@ -0,0 +1,14 @@ +// "Replace with collect" "true" +import java.util.ArrayList; +import java.util.List; + +public class Main { + public void test(Integer[] arr) { + List result = new ArrayList<>(); + for(Integer x : arr) { + if(x > 5) { + result.add(x); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArray.java new file mode 100644 index 000000000000..6d0d8f556c40 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArray.java @@ -0,0 +1,17 @@ +// "Replace with collect" "true" +import java.util.ArrayList; +import java.util.List; + +public class Main { + public List test(String[][] arr) { + List result = new ArrayList<>(); + for(String[] subArr : arr) { + if(subArr != null) { + for(String str : subArr) { + result.add(str); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArrayPrimitive.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArrayPrimitive.java new file mode 100644 index 000000000000..3a0ed029cfc0 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforeFlatten2DArrayPrimitive.java @@ -0,0 +1,17 @@ +// "Replace with forEach" "true" +import java.util.ArrayList; +import java.util.List; + +public class Main { + public List test(int[][] arr) { + List result = new ArrayList<>(); + for(int[] subArr : arr) { + if(subArr != null) { + for(int str : subArr) { + result.add(str); + } + } + } + return result; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArray.java new file mode 100644 index 000000000000..16a9a198f4c1 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/streamApiMigration/beforePrimitiveArray.java @@ -0,0 +1,10 @@ +// "Replace with forEach" "false" +public class Main { + public void test(int[] arr) { + for(int i : arr) { + if(i > 0) { + System.out.println(i); + } + } + } +} \ No newline at end of file