This question already has answers here:
forEach not modify java(8) collection
(3 answers)
Closed 4 years ago.
Looking at this code:
import java.util.Arrays;
import java.util.List;
public class LmadaExperiment {
public static void main(String args[]) {
List<String> li = Arrays.asList("One", "Two", "Three");
li.forEach(element -> element.toUpperCase());
li.forEach(System.out::print);
}
}
Guess what is the answer of this ?
Answer: Its not converted to uppercase.
Anyone knows why ?
The function toUpperCase returns the string, so you need to set element = element.toUpperCase()
forEach won’t use element as a reference. You’re not actually manipulating the element, just it’s representation.
You could either use a map, to actually manipulate the array, or System.out.print each element toUpperCase.
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class LmadaExperiment {
public static void main(String args[]) {
List<String> li = Arrays.asList("One", "Two", "Three");
List<String> li_uc= li.stream().map(String::toUpperCase).collect(Collectors.asList());
li_uc.forEach(System.out::print);
}
}
Related
I am writing a small "language" to create javascript code. Essentially it is hiding/showing some html form elements. But i need to add custom javascript code to some, e.g. what to do on a click-event.
Action:
'on' eventName=ID 'do' code=CODE
;
terminal BEGIN: "!$";
terminal END: "$!";
terminal CODE:
BEGIN -> END
;
I can now create an Eclipse-Plugin and code in my language, but the value of the field code contains the BEGIN and END characters.
on eventName do !$
var x = thisIsJavaScript();
console.log(x);
$!
My value is:
!$
var x = thisIsJavaScript();
console.log(x);
$!
I want only the part in between without !$ and $!.
Any hint is appreciated.
Thank you very much!
you should write a valueconverter for your terminal rule
import org.eclipse.xtext.common.services.DefaultTerminalConverters;
import org.eclipse.xtext.conversion.IValueConverter;
import org.eclipse.xtext.conversion.ValueConverter;
import org.eclipse.xtext.conversion.ValueConverterException;
import org.eclipse.xtext.nodemodel.INode;
import com.google.inject.Inject;
public class MyDslConverters extends DefaultTerminalConverters {
#Inject
private CODEValueConverter codeValueConverter;
#ValueConverter(rule = "CODE")
public IValueConverter<String> CODE() {
return codeValueConverter;
}
public static class CODEValueConverter implements IValueConverter<String> {
#Override
public String toValue(String string, INode node) throws ValueConverterException {
return string.substring(2, string.length()-2);
}
#Override
public String toString(String value) throws ValueConverterException {
return "!$" + value + "$!";
}
}
}
I'm implementing the CombinePerKeyExample using a subclass of CombineFn instead of using an implementation of SerializableFunction
package me.examples;
import org.apache.beam.sdk.coders.AvroCoder;
import org.apache.beam.sdk.coders.DefaultCoder;
import org.apache.beam.sdk.transforms.Combine.CombineFn;
import java.util.HashSet;
import java.util.Set;
public class ConcatWordsCombineFn extends CombineFn<String, ConcatWordsCombineFn.Accumulator, String> {
#DefaultCoder(AvroCoder.class)
public static class Accumulator{
HashSet<String> plays;
}
#Override
public Accumulator createAccumulator(){
Accumulator accumulator = new Accumulator();
accumulator.plays = new HashSet<>();
return accumulator;
}
#Override
public Accumulator addInput(Accumulator accumulator, String input){
accumulator.plays.add(input);
return accumulator;
}
#Override
public Accumulator mergeAccumulators(Iterable<Accumulator> accumulators){
Accumulator mergeAccumulator = new Accumulator();
mergeAccumulator.plays = new HashSet<>();
for(Accumulator accumulator: accumulators){
mergeAccumulator.plays.addAll(accumulator.plays);
}
return mergeAccumulator;
}
#Override
public String extractOutput(Accumulator accumulator){
//how to access the key here ?
return String.join(",", accumulator.plays);
}
}
The pipeline is composed of a ReadFromBigQuery, ExtractAllPlaysOfWords (code below) and WriteToBigQuery
package me.examples;
import com.google.api.services.bigquery.model.TableRow;
import org.apache.beam.sdk.coders.KvCoder;
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.transforms.Combine;
import org.apache.beam.sdk.transforms.PTransform;
import org.apache.beam.sdk.transforms.ParDo;
import org.apache.beam.sdk.values.KV;
import org.apache.beam.sdk.values.PCollection;
public class PlaysForWord extends PTransform<PCollection<TableRow>, PCollection<TableRow>> {
#Override
public PCollection<TableRow> expand(PCollection<TableRow> input) {
PCollection<KV<String, String>> largeWords = input.apply("ExtractLargeWords", ParDo.of(new ExtractLargeWordsFn()));
PCollection<KV<String, String>> wordNPlays = largeWords.apply("CombinePlays",Combine.perKey(new ConcatWordsCombineFn()));
wordNPlays.setCoder(KvCoder.of(StringUtf8Coder.of(), StringUtf8Coder.of()));
PCollection<TableRow> rows = wordNPlays.apply("FormatToRow", ParDo.of(new FormatShakespeareOutputFn()));
return rows;
}
}
I would like to access the key in ConcatWordsCombineFn in order to do the final accumulation based on that. An example can be to join the words with , if the key begins with an a or use ; otherwise.
When looking at the programming guide
If you need the combining strategy to change based on the key (for example, MIN for some users and MAX for other users), you can define a KeyedCombineFn to access the key within the combining strategy.
I couldn't find KeyedCombineFn in org.apache.beam.sdk.transforms.Combine
I'm using Apache Beam 2.12.0 and Google Dataflow as a runner.
I don't think there is a built-in way to solve this. The straightforward workaround (not perfect, I know) is to wrap your string into another KV: KV<String, KV<String, String>> where both keys are the same.
I'm trying to create a Map from a List using Streams.
The key should be the name of the original item,
The value should be some derived data.
After .map() the stream consists of Integers and at the time of .collect() I can't access "foo" from the previous lambda. How do I get the original item in .toMap()?
Can this be done with Streams or do I need .forEach()?
(The code below is only for demonstration, the real code is of course much more complex and I can't make doSomething() a method of Foo).
import java.util.ArrayList;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class StreamTest {
public class Foo {
public String getName() {
return "FOO";
}
public Integer getValue() {
return 42;
}
}
public Integer doSomething(Foo foo) {
return foo.getValue() + 23;
}
public Map<String, Integer> run() {
return new ArrayList<Foo>().stream().map(foo -> doSomething(foo)).collect(Collectors.toMap(foo.getName, Function.identity()));
}
public static void main(String[] args) {
StreamTest streamTest = new StreamTest();
streamTest.run();
}
}
It appears to me it’s not that complicated. Am I missing something?
return Stream.of(new Foo())
.collect(Collectors.toMap(Foo::getName, this::doSomething));
I’m rather much into method references. If you prefer the -> notation, use
return Stream.of(new Foo())
.collect(Collectors.toMap(foo -> foo.getName(), foo -> doSomething(foo)));
Either will break (throw an exception) if there’s more than one Foo with the same name in your stream.
I am using the jface tableviewer in an eclipse rcp application to display some values.
Therefore I have written the following snipped ...
tableviewer = new TableViewer(container, SWT.FULL_SELECTION | SWT.BORDER | SWT.SINGLE);
tableviewer.setContentProvider(new ArrayContentProvider());
ColumnViewerToolTipSupport.enableFor(tableviewer, ToolTip.RECREATE);
final Table table = tableviewer.getTable();
table.setHeaderVisible(true);
table.setLinesVisible(true);
TableViewerColumn column = new TableViewerColumn(tableviewer, SWT.NONE);
column.getColumn().setText("col1");
column.getColumn().setResizable(true);
column.setLabelProvider(new ConfigLabelProvider("col1"));
And here here ConfigLabelProvider definition
private class ConfigLabelProvider extends StyledCellLabelProvider {
private String property;
public ConfigLabelProvider(String property) {
this.property = property;
}
#Override
public void update(ViewerCell cell) {
GenericConfigInterfaceEntity config = (GenericConfigInterfaceEntity) cell.getElement();
switch (property) {
case "col1":
cell.setText(AppHelper.preventNull("col1Text col1Text col1Text col1Text col1Text"));
break;
case ...
}
super.update(cell);
}
}
Now my problem is if the column is too small, the default tooltip is displayed trying to show the full cell text value.
BUT I get a tooltip box that is large enough for the whole text but the text isn't shown outside the cell rectange.
If I extend the ConfigLabelProvider from CellLabelProvider the Tooltip is showing up like expected ...
But I need the paint method of the StyledCellLabelProvider.
Any ideas?
Edit 1
I have written a small Java Example Project using SWT and JFACE, because my problems still remain.
My goal is to have an table with a cell-Background without the mousehover (because its looking ugly together) and a custom tooltip.
Here's my TestTable implementation
package main;
import java.util.ArrayList;
import java.util.List;
import model.TestModel;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.StyledCellLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.jface.viewers.ViewerColumn;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
public class TestTable extends Dialog {
private TableViewer tableviewer;
private List<TestModel> entities;
protected TestTable(Shell parentShell) {
super(parentShell);
}
#Override
public void create() {
super.create();
loadData();
}
#Override
protected Control createDialogArea(Composite parent) {
GridData dataLayout;
Composite area = (Composite) super.createDialogArea(parent);
dataLayout = new GridData(GridData.FILL_BOTH);
dataLayout.heightHint = 150;
dataLayout.widthHint = 500;
Composite wrapper = new Composite(area, SWT.NONE);
wrapper.setLayoutData(dataLayout);
wrapper.setLayout(new FillLayout());
tableviewer = new TableViewer(wrapper, SWT.BORDER | SWT.MULTI);
tableviewer.setContentProvider(new ArrayContentProvider());
ColumnViewerToolTipSupport.enableFor(tableviewer);
final Table table = tableviewer.getTable();
table.setLinesVisible(true);
table.setHeaderVisible(true);
createColumns(wrapper);
return area;
}
private void createColumns(Composite wrapper) {
TableViewerColumn firstnameColumn = new TableViewerColumn(tableviewer, SWT.NONE);
firstnameColumn.getColumn().setText("Vorname");
firstnameColumn.setLabelProvider(new StyledCellLabelProvider(StyledCellLabelProvider.COLORS_ON_SELECTION) {
#Override
public void initialize(ColumnViewer viewer, ViewerColumn column) {
super.initialize(viewer, column);
this.setOwnerDrawEnabled(false);
}
#Override
public void update(ViewerCell cell) {
TestModel model = (TestModel) cell.getElement();
cell.setText(model.getFirstname());
cell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GREEN));
}
#Override
public String getToolTipText(Object element) {
TestModel model = (TestModel) element;
return "USE THIS AS TOOLTIP";
}
});
TableViewerColumn lastnameColumn = new TableViewerColumn(tableviewer, SWT.NONE);
lastnameColumn.getColumn().setText("Nachname");
lastnameColumn.setLabelProvider(new StyledCellLabelProvider(StyledCellLabelProvider.COLORS_ON_SELECTION) {
#Override
public void initialize(ColumnViewer viewer, ViewerColumn column) {
super.initialize(viewer, column);
this.setOwnerDrawEnabled(false);
}
#Override
public void update(ViewerCell cell) {
TestModel model = (TestModel) cell.getElement();
cell.setText(model.getLastname());
cell.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GREEN));
}
#Override
public String getToolTipText(Object element) {
TestModel model = (TestModel) element;
return "USE THIS AS TOOLTIP";
}
});
for (TableColumn c : tableviewer.getTable().getColumns()) {
c.pack();
}
}
private void loadData() {
entities = new ArrayList<TestModel>();
entities.add(new TestModel("___Firstname1___", "Lastname1", "Username1", "Kommentar"));
entities.add(new TestModel("___Firstname2___", "Lastname2", "Username2", "Kommentar"));
entities.add(new TestModel("___Firstname3___", "Lastname3", "Username3", "Kommentar"));
entities.add(new TestModel("___Firstname4___", "Lastname4", "Username4", "Kommentar"));
entities.add(new TestModel("___Firstname5___", "Lastname5", "Username5", "Kommentar"));
tableviewer.setInput(entities);
tableviewer.refresh();
}
}
And here are some faulty pictures
Here the native TableViewer Tooltip and my custom ToolTip is shown, also the row gets selected (COLORS_ON_SELECTION should prevent that)
Here no tooltip is shown on the second column
And here no tooltip is shown and as you can see the first cell isn't filled up
If I add SWT.FULL_SELECTION the tooltip on column 2 appears but the other issues remain.
I think it's a kind of buggy that Tooltip Support or I am doing it totally wrong.
This solved my problem
https://stackoverflow.com/a/28991593/1822033
The underlaying second tip was shown because the column was too narrow. Setting tableviewer.getTavle().setTooltipText(""); stopped showing the native tip.
Setting it to null displays it anyway!
I have a scene with a NumberSpinner element and a ComboBox element and I want to bind the minValue property of the NumberSpinner element with the valueProperty of the ComboBox element. Some code:
#FXML
private NumberSpinner aNumberSpinner;
#FXML
private ComboBox<Unit> aComboBox;
where Unit is an enum:
public enum Unit {
mm,
degree
}
What I want is that when I choose degree Unit in aComboBox the minValueProperty() of aNumberSpinner become 10. How can I achieve it?
As suggested by Kleopatra in comments it is best if the unit knows its own minimum.
Preferred solution - no binding
My preferred solution for this wouldn't use a binding at all.
A listener on the combobox value can easily set the minimum value of your spinner object directly to the appropriate value by querying the minimum value from the unit newly selected in the combo box.
Sometimes it is possible to be a bit too tricky with bindings...
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class UnitMinimums extends Application {
private enum Unit {
mm(0), degree(10);
private final int minValue;
private Unit(int minValue) {
this.minValue = minValue;
}
public int getMinValue() {
return minValue;
}
}
private Slider slider = new Slider(0, 20, 0);
private ComboBox<Unit> combo = new ComboBox<>(
FXCollections.observableArrayList(
Unit.values()
)
);
#Override
public void start(Stage stage) throws Exception {
combo.valueProperty().addListener((observable, oldValue, newValue) ->
slider.setMin(newValue.getMinValue())
);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
VBox layout = new VBox(5, slider, combo);
layout.setPadding(new Insets(10));
VBox.setVgrow(combo, Priority.ALWAYS);
combo.setMaxWidth(Double.MAX_VALUE);
combo.getSelectionModel().select(0);
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Pure Binding Solution
If you did want a pure binding solution, you could do something like below, but it has the disadvantage of scattering the information specific to the minimum value of the unit (which is intrinsic to the enum) all around the code if you started writing code like this a lot.
Use Bindings.when:
Bindings.when(
combo.valueProperty().isEqualTo(Unit.degree)
).then(10)
.otherwise(0)
Executable Sample
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
public class BoundMinimums extends Application {
private enum Unit { mm, degree }
private Slider slider = new Slider(0, 20, 0);
private ComboBox<Unit> combo = new ComboBox<>(
FXCollections.observableArrayList(
Unit.values()
)
);
#Override
public void start(Stage stage) throws Exception {
slider.minProperty().bind(
Bindings.when(
combo.valueProperty().isEqualTo(Unit.degree)
).then(10)
.otherwise(0)
);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
VBox layout = new VBox(5, slider, combo);
layout.setPadding(new Insets(10));
VBox.setVgrow(combo, Priority.ALWAYS);
combo.setMaxWidth(Double.MAX_VALUE);
stage.setScene(new Scene(layout));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
On datatype conversion
This gets a little complicated and non-obvious for me (which is another reason to sometimes prefer listeners and straight setters over binding), but I think you can do something like below, which coverts the DoubleProperty slider.minProperty() to an ObjectProperty<Integer>:
ObjectProperty<Integer> op = new SimpleObjectProperty<>(5);
op.bind(
IntegerExpression.integerExpression(
slider.minProperty()
).asObject()
);
Putting it together with the unit conversion, you get the following, which maybe even does what you want:
ObjectProperty<Integer> op = new SimpleObjectProperty<>(5);
op.bind(
IntegerExpression.integerExpression(
Bindings.when(
combo.valueProperty().isEqualTo(Unit.degree)
).then(10)
.otherwise(0)
).asObject()
);